W3TPL: Difference between revisions

From Woozle Writes Code
Jump to navigation Jump to search
(New page: ==Overview== category:software/incompleteW3TPL, which stands for Woozle's Wacky Wiki Text Processing Language, is a scripting language extension for [[Media...)
 
No edit summary
 
(13 intermediate revisions by the same user not shown)
Line 1: Line 1:
==Overview==
[[category:MediaWiki extension]]
[[category:software/incomplete]][[W3TPL]], which stands for [[User:Woozle|Woozle]]'s Wacky [[Wiki]] Text Processing Language, is a [[scripting]] language extension for [[MediaWiki]]. It is currently in development, although it does perform some useful functions as-is.
==About==
==Code==
[[W3TPL]], which stands for Woozle's Wacky Wiki Text Processing Language, is a scripting language [[MWX|extension for MediaWiki]]. It was written to permit some simple scripting and to get around certain restrictions of the wikitext format (e.g. emitting "dangerous" tags). It has largely been superceded by new options and other MediaWiki extensions that are better supported (such as {{l/mw/ext|Scribunto}}), and some tags/options do not currently work.
This is just a snapshot from my editor, which I haven't even saved; it might not run. I should have a runnable version later today.
===Pages===
 
* [[/recipes]]: useful snippets for W3TPL
All the tags except <w3tpl> work, but parser interactions make them problematic for more complex applications.
* [[/tags]]: tags defined for use within wikitext
<php><?php
* [[/sysdata]]: syntax for accessing system data
/*
* [[/test suite]]: code to verify that W3TPL is working properly
HISTORY:
* [[/history]]: change log
0.01 (Wzl) Mainly proof-of-concept;
* [[/dev]]: bits & pieces under development
parser should later be optimized for execution time by using PHP intrinsic string fx instead of PHP-code loop
* [[/archive]]: obsolete stuff
0.02 (Wzl) Kluge to let <xploop> pull #var value under MW <1.12
==Links==
TO DO: If page is not protected, pre should be forced FALSE and post should be forced TRUE
* [https://gitlab.com/woozalia/w3tpl GitLab]: official code repository
"pre" can do weird things
==Technical Notes==
"post" set false allows raw HTML
W3TPL gets initialized like this:
0.03 (Wzl) <func> and related tags seem to be working
* {{l/mw|Manual:Hooks/ParserFirstCallInit}} (MediaWiki hook)
0.04 (Wzl) Some debugging; now works with v1.12 {{#tag}} function and template parameters (but not very well)
* &rarr; <code>w3tpl\cEntryPoint::cbInit</code>
names are always lowercased because sometimes the parser does it for you
names are always trimmed, because sometimes the parser includes extra spaces
0.05 (Wzl) Added variable indirection ($); removed now-redundant "namer" attribute from <let>
can we do something similar with pre-parsing? (i.e. a character to indicate the need for it -- @(stuff to parse))
<if> can now make more sense, i.e. using actual values instead of assuming variable names
0.06 (Wzl) xploop now using variable indirection; removed listvar parameter
0.07 (Wzl) Execution trace in <dump>
0.08 (Wzl) <trace> to set trace options; "input" option in <call>
0.09 (Wzl) <echo> tag; <call> does not output its contents
BUGS:
$wgW3_func needs to be an array, so you can do <call...><arg><arg></call> and then pass the return value as an argument to another function
ELEMENTS:
<hide>: Runs the parser on everything in between the tags, but doesn't display the result.
Useful for doing a lot of "programmish" stuff, so you can format it nicely and comment it without messing up your display
<let>, <get>: much like PageVars extension, but using XML tags instead of {{#parser}} functions
<func>: defines a function which can be called with arguments later
<arg>: optional method of passing arguments to a function
<call>: call a previously defined function
<dump>: show list of all variables (with values) and functions (with code)
<if>, <else>: control structure
<xploop list="\demarcated\list" repl=string-to-replace sep=separator></xploop>: Same as {{#xploop}}, but uses varname instead of $s$
TO-DO <w3tpl></w3tpl>: The language itself
*/
 
$wgExtensionCredits['other'][] = array(
        'name' => 'W3TPL',
        'description' => 'Woozle\'s Wacky Wiki Text Processing Language',
        'author' => 'Woozle (Nick) Staddon',
'version' => '0.09 2008-08-24 (in progress)'
);
 
define(ksFuncInit,'efW3TPLInit');
 
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980
if ( defined( 'MW_SUPPORTS_PARSERFIRSTCALLINIT' ) ) {
        $wgHooks['ParserFirstCallInit'][] = ksFuncInit;
} else { // Otherwise do things the old fashioned way
        $wgExtensionFunctions[] = ksFuncInit;
}
$wgHooks['LanguageGetMagic'][] = 'efW3_LanguageGetMagic';
 
 
function efW3TPLInit() {
        global $wgParser;
global $wgExtW3TPL;
 
// hook in <tag>-style functions:
        $wgParser->setHook( 'hide', 'efW3Hide' );
        $wgParser->setHook( 'let', 'efW3Let' );
        $wgParser->setHook( 'get', 'efW3Get' );
        $wgParser->setHook( 'echo', 'efW3Echo' );
        $wgParser->setHook( 'dump', 'efW3Dump' );
        $wgParser->setHook( 'trace', 'efW3Trace' );
        $wgParser->setHook( 'if', 'efW3If' );
        $wgParser->setHook( 'else', 'efW3Else' );
        $wgParser->setHook( 'func', 'efW3Func' );
        $wgParser->setHook( 'call', 'efW3Call' );
        $wgParser->setHook( 'arg', 'efW3Arg' );
        $wgParser->setHook( 'load', 'efW3Load' );
        $wgParser->setHook( 'xploop', 'efW3Xploop' );
        $wgParser->setHook( 'w3tpl', 'efW3TPLRender' );
 
// hook in {{#parser}}-style functions:
$wgExtW3TPL = new W3TPL_fx ( );
$wgParser->setFunctionHook ( 'w3xploop', array ( &$wgExtW3TPL, 'runXploop'    ) );
$wgParser->setFunctionHook ( 'w3xpcount', array ( &$wgExtW3TPL, 'runXpCount'  ) );
$wgParser->setFunctionHook ( 'let', array ( &$wgExtW3TPL, 'runLet'  ) );
$wgParser->setFunctionHook ( 'get', array ( &$wgExtW3TPL, 'runGet'  ) );
        return true;
}
function efW3_LanguageGetMagic( &$magicWords, $langCode = "en" ) {
    switch ( $langCode ) {
        default:
            $magicWords['w3xploop'] = array ( 0, 'w3xploop' );
            $magicWords['w3xpcount'] = array ( 0, 'w3xpcount' );
    }
    return true;
}
 
function TrueFalse($iVar) {
return $iVar?'TRUE':'FALSE';
}
function W3VarExists($iName) {
global $wgW3Vars;
 
$strName = strtolower($iName);
return isset($wgW3Vars[$strName]);
}
function W3KillVar($iName) {
global $wgW3Vars;
 
$strName = strtolower($iName);
unset($wgW3Vars[$strName]);
}
function W3SetVar($iName, $iValue) {
global $wgW3Vars, $wgW3_traceVars;
 
$strName = strtolower($iName);
$wgW3Vars[$strName] = $iValue;
if ($wgW3_traceVars) {
W3AddTrace(' ['.ShowHTML($strName).'] <= ['.$iValue.']');
}
}
function W3GetExpr($iName) {
// very simple parser which recursively checks for "$", and returns value of var if found;
// otherwise returns original string.
global $wgW3Vars, $wgW3_traceVars;
global $wgW3Trace_indent;
 
$wgW3Trace_indent++;
$strName = $iName;
if ($wgW3_traceVars) {
W3AddTrace(' {GETEXPR ['.ShowHTML($iName).']');
}
do {
$chFirst = substr($strName,0,1);
if ($chFirst == '$') {
$isInd = true;
$strRef = strtolower(substr($strName,1));
$strName = W3GetVal($strRef);
} else {
$isInd = false;
}
} while ($isInd);
if ($wgW3_traceVars) {
W3AddTrace(' => ['.ShowHTML($strName).'] GETEXPR}');
}
$wgW3Trace_indent--;
return $strName;
}
function W3GetVal($iName) {
// gets value of given variable
// checks function arguments, if function is defined
global $wgW3Vars,$wgW3_traceVars;
global $wgW3Trace_indent;
 
$wgW3Trace_indent++;
if ($wgW3_traceVars) {
W3AddTrace('{GETVAL ['.ShowHTML($iName).']');
}
$strName = strtolower(W3GetExpr($iName)); // follow any indirections and get ultimate value
if (isset($wgW3Vars[$strName])) {
$strVal = $wgW3Vars[$strName];
} else {
$strVal = NULL;
}
if ($wgW3_traceVars) {
W3AddTrace('['.ShowHTML($strName).'] => ['.ShowHTML($strVal).'] GETVAL}');
}
$wgW3Trace_indent--;
return $strVal;
}
function W3AddTrace($iLine,$iInd=0) {
global $wgW3Trace, $wgW3Trace_indents, $wgW3Trace_indent;
 
$wgW3Trace[] = $iLine;
$wgW3Trace_indents[] = $wgW3Trace_indent;
$wgW3Trace_indent += $iInd;
}
 
function efW3Hide( $input, $args, $parser ) {
$parser->recursiveTagParse( $input );
return NULL;
}
function efW3Let( $input, $args, $parser ) {
global $wgW3Vars;
 
$strCopy = NULL;
 
$strNameRaw = $args['name'];
// trim whitespace and check for redirection:
$strName = strtolower(W3GetExpr(trim($strNameRaw)));
 
if (isset($args['copy'])) {
$strCopy = $args['copy'];
$strVal = W3GetVal($strCopy);
} else {
$strVal = $input;
}
if (isset($args['pre'])) {
$strVal = $parser->recursiveTagParse($strVal);
// $strVal = $parser->replaceVariables($input);
}
$strTrace = 'LET &ldquo;'.$strName;
if ($strName != $strNameRaw) {
$strTrace .= ' ('.$strNameRaw.')';
}
$strTrace .= '&rdquo; = &ldquo;'.$strVal.'&rdquo;';
if ($strCopy) {
$strTrace .= ' copied from <u>'.$strCopy.'</u>';
}
W3AddTrace($strTrace);
if (isset($args['append'])) {
$wgW3Vars[$strName] .= $strVal;
} else {
$wgW3Vars[$strName] = $strVal;
}
if (isset($args['echo'])) {
return $strVal;
} else {
return NULL;
}
}
function efW3Get( $input, $args, $parser ) {
$strName = strtolower($args['name']);
if (isset($args['parsename'])) {
$strName = $parser->recursiveTagParse($strName);
}
$strVal = W3GetVal($strName);
if (isset($args['strip'])) {
$strVal = ShowHTML($strVal);
} else {
$strVal = $parser->recursiveTagParse($strVal);
}
if (isset($args['len'])) {
$strVal = substr($strVal,0,$args['len']);
}
return $strVal;
}
function efW3Echo( $input, $args, $parser ) {
global $wgW3_ifDepth,$wgW3_funcOutput;
 
if (isset($args['strip'])) {
$out = ShowHTML($input);
} else {
$out = $parser->recursiveTagParse($input);
}
W3AddTrace('ECHO ['.ShowHTML($input).']');
$wgW3_funcOutput[$wgW3_ifDepth] .= $out;
}
function efW3Dump( $input, $args, $parser ) {
global $wgW3Vars, $wgW3_funcs, $wgW3Trace;
global $wgW3Trace_indents;
 
$out = '<ul>';
if (is_array($wgW3Vars)) {
$out .= '<li><b>Variables</b>:<ul>';
foreach ($wgW3Vars as $name => $value) {
$out .= '<li> ['.$name.'] = ['.$value.']';
}
$out .= '</ul>';
} else {
$out .= '<li><i>No variables set</i>';
}
if (is_array($wgW3_funcs)) {
$out .= '<li><b>Functions</b>:<ul>';
foreach ($wgW3_funcs as $name => $obj) {
$out .= '<li>'.$obj->dump();
}
$out .= '</ul>';
} else {
$out .= '<li><i>No functions defined</i>';
}
if (isset($args['trace'])) {
if (is_array($wgW3Trace)) {
$out .= '<li><b>Trace</b>:<ul>';
foreach ($wgW3Trace as $idx => $line) {
$indLine = $wgW3Trace_indents[$idx];
if ($indLine > $indCur) {
$out .= '<ul>';
} elseif ($indLine < $indCur) {
$out .= '</ul>';
}
$indCur = $indLine;
$out .= '<li><b>'.$idx.'</b> '.$line;
}
$out .= '</ul>';
} else {
$out .= '<li><i>No trace events</i>';
}
}
$out .= '</ul>';
return $out;
}
function efW3Trace( $input, $args, $parser ) {
global $wgW3_traceVars;
 
$wgW3_traceVars = isset($args['assigns']);
}
function efW3If( $input, $args, $parser ) {
global $wgW3Vars,$wgW3_ifFlag,$wgW3_ifDepth,$wgW3_funcOutput;
 
$wgW3_ifDepth++;
$ifFlag = false;
if (isset($args['flag'])) {
$strName = $args['flag'];
$strVal = W3GetVal($strName);
if (is_null($strVal) || ($strVal == '')) {
$ifFlag = FALSE;
$dbgType = 'blank';
} else if (is_numeric($strVal)) {
$ifFlag = ($strVal != 0);
$dbgType = 'numeric';
} else {
$ifFlag = TRUE;
$dbgType = '';
}
W3AddTrace(' IF('.$wgW3_ifDepth.'): ['.$strVal.']  != 0: ['.TrueFalse($ifFlag).']:'.$dbgType);
} elseif (isset($args['comp'])) {
$strName = $args['comp'];
$strVal1 = W3GetVal($strName);
$strName = $args['with'];
$strVal2 = W3GetVal($strName);
if (isset($args['pre'])) {
$strVal1 = $parser->recursiveTagParse($strVal1);
$strVal2 = $parser->recursiveTagParse($strVal2);
// $strVal1 = $parser->replaceVariables($strVal1);
// $strVal2 = $parser->replaceVariables($strVal2);
 
}
$ifFlag = ($strVal1 == $strVal2);
}
if ($ifFlag) {
$out = $parser->recursiveTagParse($input);
} else {
$out = NULL;
}
$wgW3_ifFlag[$wgW3_ifDepth] = $ifFlag;
// W3AddTrace('SETTING IFFLAG['.$wgW3_ifDepth.']=>['.TrueFalse($ifFlag).']');
// $out .= $wgW3_funcOutput[$wgW3_ifDepth];
// $wgW3_funcOutput[$wgW3_ifDepth] = NULL; // clear the accumulated echo output
$wgW3_ifDepth--;
return $out;
}
function efW3Else( $input, $args, $parser ) {
global $wgW3_ifFlag, $wgW3_ifDepth, $wgW3_funcOutput;
 
$wgW3_ifDepth++;
$ifFlag = $wgW3_ifFlag[$wgW3_ifDepth];
// W3AddTrace('GETTING IFFLAG['.$wgW3_ifDepth.']=>['.TrueFalse($ifFlag).']');
W3AddTrace(' ELSE('.$wgW3_ifDepth.'): ['.$ifFlag.']');
if ($ifFlag) {
W3AddTrace('ELSE skipped');
$out = NULL;
} else {
W3AddTrace('ELSE executed');
$out = $parser->recursiveTagParse($input);
// W3AddTrace('ELSE: OUT = ['.ShowHTML($out).']');
W3AddTrace('ELSE: OUT = ['.$out.']('.ShowHTML($out).')');
}
$strSaved .= $wgW3_funcOutput[$wgW3_ifDepth];
$out .= $strSaved;
W3AddTrace('ELSE: ADDING ['.$strSaved.']('.ShowHTML($strSaved).')');
$wgW3_funcOutput[$wgW3_ifDepth] = NULL; // clear the accumulated echo output
 
$wgW3_ifDepth--;
$wgW3_funcOutput[$wgW3_ifDepth] .= $out;
return $out;
}
function efW3Func( $input, $args, $parser ) {
global $wgW3_funcs;
 
foreach ($args as $name => $value) {
if ($pcnt) {
/*
The parser apparently sets the argument's value to its name if no value is specified.
This is a sort of bug for this purpose, but maybe it makes sense in other contexts.
The real way to get around it is to use <w3tpl> block syntax instead of the <func> tag.
*/
if ($value != $name) {
$funcArgs[$name] = $value;
} else {
$funcArgs[$name] = null;
}
} else {
$funcName = strtolower($name);
}
$pcnt++;
}
W3AddTrace('FUNC &ldquo;'.$funcName.'&rdquo;');
$objFunc = new clsW3Function($parser,$funcName,$funcArgs,$input);
$wgW3_funcs[$funcName] = $objFunc;
return NULL;
}
function efW3Call( $input, $args, $parser ) {
global $wgW3_funcs,$wgW3_func,$wgW3_ifDepth,$wgW3_funcOutput;
 
$pcnt = 0;
foreach ($args as $name => $value) {
$strName = strtolower(trim($name));
if ($pcnt) {
$strVal = W3GetExpr($value);
$strTrace .= $objFunc->LoadArg($strVal,$strName);
$strTrace .= ' ';
} else {
$funcName = $strName;
$strTrace = 'CALL '.$funcName.'( ';
$objFunc = $wgW3_funcs[$funcName];
$wgW3_func = $objFunc;
if (!is_object($objFunc)) {
$out = 'ERROR: Function "'.$funcName.'" is undefined.';
return $out;
}
$objFunc->ResetArgs();
}
$pcnt++;
}
$strTrace .= ')';
if ($input) {
// $strTrace .= ' INPUT: {'.ShowHTML($input).'}';
$res = $parser->recursiveTagParse($input);
// $strTrace .= ' PARSED: {'.ShowHTML($res).'}';
}
W3AddTrace($strTrace);
$out = $objFunc->execute();
// LATER: implement "echo" option to include parsed contents of function
$out = $wgW3_funcOutput[$wgW3_ifDepth];
$wgW3_funcOutput[$wgW3_ifDepth] = NULL; // clear the accumulated echo output
$wgW3_func = NULL; // no active function (is this still used?)
return $out;
}
function efW3Arg( $input, $args, $parser ) {
global $wgW3_func;
 
if (isset($args['name'])) {
$name = $args['name'];
} else {
$name = '';
}
if (isset($args['pre'])) {
$value = $parser->recursiveTagParse($input);
} else {
$value = $input;
}
$strTrace = ' +ARG: '.$wgW3_func->LoadArg($value,$name);
W3AddTrace($strTrace);
}
function efW3Load( $input, $args, $parser ) {
global $wgParser,$wgTitle;
 
$strTitle = $args['page'];
$strTitle = W3GetExpr($strTitle);
$doEcho = isset($args['echo']);
W3AddTrace('LOAD {'.$strTitle.'}');
// Some pages apparently don't create the parser; if this code needs to run on one of those pages,
// then this may need to create $wgParser if it doesn't exist. For now, we assume optimistically.
$objTitle = Title::newFromText($strTitle);
$objArticle = new Article($objTitle);
 
$txtContent = $objArticle->getContent();
$out = $parser->recursiveTagParse($txtContent);
if ($doEcho) {
return $out;
}
}
function efW3Xploop( $input, $args, $parser ) {
global $wgW3Vars,$wgW3_ifDepth,$wgW3_funcOutput;
 
$strListRaw = $args['list'];
$strList = W3GetExpr($strListRaw);
$strTok = $args['repl'];
$doEcho = isset($args['echo']);
if (isset($args['var'])) {
$strVar = strtolower($args['var']); // THIS IS GETTING SET TO WEIRD UNIQ thing?
} else {
$strVar = NULL;
}
if (isset($args['sep'])) {
$sepStr = $args['sep'];
} else {
$sepStr = NULL;
}
if ($strTok) {
// doing a straight token replacement
$strTrace = 'XPLOOP replace ('.ShowHTML($strTok).') <= &ldquo;'.ShowHTML($strList).'&rdquo;';
} else {
// setting variable value
$strTrace = 'XPLOOP set ('.ShowHTML($strVar).') <= &ldquo;'.ShowHTML($strList).'&rdquo;';
}
if ($strList != $strListRaw) {
$strTrace .= '<=&ldquo;'.$strListRaw.'&rdquo;';
}
W3AddTrace($strTrace);
if (isset($args['parselist'])) {
$strList = $parser->recursiveTagParse( $strList );
}
 
$tok = substr ( $strList, 0, 1); // token for splitting
if ($tok) {
$tks = substr ( $strList, 1 ); // tokenized string
$list = explode ( $tok, $tks ); // split the string
$out = '';
} else {
return NULL;
}
if ($strTok) {
// doing a straight token replacement
foreach ($list as $value) {
if ($out) {
$out .= $sepStr;
}
$out .= str_replace( $strTok, $value, $input );
}
$out = CharacterEscapes::charUnesc( $out, array(), $parser );
$out = $parser->recursiveTagParse( $out );
} else {
foreach ($list as $value) {
if ($out) {
$out .= $sepStr;
}
$wgW3Vars[$strVar] = $value;
W3AddTrace(' - XP: ['.$strVar.'] <- ['.$value.']');
$out .= $parser->recursiveTagParse( $input );
}
}
if ($doEcho) {
return $out ;
} else {
$out = $wgW3_funcOutput[$wgW3_ifDepth];
$wgW3_funcOutput[$wgW3_ifDepth] = NULL; // clear accumulated echo output
return $out;
}
}
 
function efW3TPLRender( $input, $args, $parser ) {
global $w3step;
 
$out = $input;
if (isset($args['step'])) {
$w3step = true; // show each line of code before it is executed
}
if (isset($args['pre'])) {
$out = $parser->recursiveTagParse( $out );
}
if (!isset($args['notpl'])) {
$out = ActualRender($out,$args);
}
if (isset($args['post'])) {
$out = $parser->recursiveTagParse( $out );
}
$out = ActualRender($out);
return $out;
}
 
function ActualRender($input) {
// break the code up into separate commands
$cmdObj = new clsW3Command();
$inQuo = FALSE;
$brDepth = 0;
$paDepth = 0;
$line = '';
$clause = '';
for ($i = 0; $ch=substr($input,$i,1); $i++) {
$isTok = FALSE;
$doAdd = TRUE;
$doSave = FALSE;
switch ($ch) {
  // whitespace
  case ' ': // space
  case "\t": // tab
if (!$inQuo) {
$isTok = TRUE;
}
break;
  case '"':
if (!$inEsc) {
$inQuo != $inQuo;
}
break;
  case '\\':
$inEsc = true;
break;
  case '(':
if (!$inQuo) {
$paDepth++;
}
break;
  case ')':
if (!$inQuo) {
$paDepth--;
if ($paDepth == 0) {
$isArgs = TRUE;
}
}
break;
  case '{':
if (!$inQuo) {
$brDepth++;
$doAdd = false; // don't include braces in $clause
}
break;
  case '}':
if (!$inQuo) {
$brDepth--;
if ($brDepth == 0) {
// end of braces is equivalent to semicolon
$doSave = true;
$doAdd = false; // don't include braces in $clause
}
}
break;
  case ';':
if (!$inQuo) {
if ($brDepth == 0) {
$doSave = true;
$doAdd = false;
}
}
break;
  case "\n":
$doAdd = false; // don't include linebreaks in $clause
break;
  default:
}
if ($doAdd) {
if ($brDepth) {
$clause .= $ch;
} else {
$line .= $ch;
}
$inEsc = false;
}
if ($doSave) {
W3AddTrace('TPL: LINE=[<u>'.$line.'</u>] CLAUSE=[<u>'.$clause.'</u>]');
$out .= $cmdObj->execute($line,$clause);
$line = '';
$clause = '';
$doSave = false;
}
}
// final semicolon not required:
if ($line) {
$out .= $cmdObj->execute($line,$clause);
}
return $out;
}
 
class clsW3Command {
private $statemt;
private $clause;
 
public function clsW3Command($iStatemt='', $iClause='') {
$this->init($iStatemt, $iClause);
}
public function init($iStatemt, $iClause) {
$this->statemt = trim($iStatemt);
$this->clause = $iClause;
}
public function execute($iStatemt, $iClause) { // init + exec
$this->init($iStatemt, $iClause);
return $this->exec();
}
public function exec() {
global $w3step;
$strStmt = $this->statemt;
if ($w3step) {
$out = '<br><b>CMD</b>: {'.$strStmt.'} <b>CLAUSE</b>: {'.$this->clause.'}';
}
/*
A command is in any of these forms:
variable action-operator expression;
expression;
keyword (expression) {clause} [keyword (expression) {clause} ... ];
An expression is in any of these forms:
function(expression[, expression[, ...]])
variable compare-operator expression
variable
constant
A constant is either a quoted string or a number
A variable is invoked by name
 
 
*/
// parse the command:
for ($i = 0; $ch=substr($strStmt,$i,1); $i++) {
$isArgs = FALSE;
if ($isTok) {
if (!$inQuo) {
if ($cmd == '') {
$cmd = $phrase;
$phrase = '';
}
} elseif ($isArgs) {
$args = $phrase;
$phrase = '';
} else {
$phrase .= $ch;
}
}
W3AddTrace('TPL layer 2: CMD=[<u>'.$cmd.'</u>] ARGS=[<u>'.$args.'</u>] leftover=[<u>'.$phrase.'</u>]');
// return $out;
}
}
 
function ShowHTML($iText) {
$out = str_replace ( '<','&lt;',$iText );
$out = str_replace ( '>','&gt;',$out);
$out = str_replace ( chr(7),'<b>^G</b>',$out);
return $out;
}
 
/*
class w3expr {
private $text;
abstract function Parse($iTask);
} */
 
class clsW3Function {
var $vParser;
var $vName, $vParams, $vCode;
var $vArgs, $vArgIdx;
 
public function clsW3Function($iParser, $iName, $iParams, $iCode) {
$this->vParser = $iParser;
$this->vName = $iName;
$this->vParams = $iParams;
$this->vCode = $iCode;
}
public function dump() {
$out = '<b>'.$this->vName.'</b>(';
if (is_array($this->vParams)) {
foreach ($this->vParams as $name => $value) {
if ($pcnt) {
$out .= ', ';
}
$out .= '<u>'.$name.'</u>';
if (isset($value)) {
$out .= '='.$value;
}
$pcnt++;
}
}
$out .= ') {';
$strCode = ShowHTML($this->vCode);
$out .= '<pre>'.$strCode.'</pre>}';
return $out;
}
public function ResetArgs() {
$this->vArgIdx = 0;
unset($this->vArgs);
}
public function LoadArg($iValue,$iName='') {
if ($iName) {
$strName = strtolower($iName);
} else {
$strName = $this->ParamName($this->vArgIdx);
$this->vArgIdx++;
}
$this->vArgs[$strName] = $iValue;
return '[<u>'.$strName.'</u>]=&ldquo;'.$iValue.'&rdquo;';
}
public function HasArg($iName) {
return isset($this->vArgs[$iName]);
}
public function ArgVal($iName) {
return $this->vArgs[$iName];
}
public function ParamName($iIndex) {
$keys = array_keys($this->vParams);
$key = $keys[$iIndex];
return $key;
}
public function execute() {
// set variables from passed arguments
if (is_array($this->vArgs)) {
foreach ($this->vArgs as $name => $value) {
if (W3VarExists($name)) {
$oldVars[$name] = W3GetVar($name);
}
W3SetVar($name, $value);
}
}
// parse (execute) the function code
$out = $this->vParser->recursiveTagParse( $this->vCode );
// restore original variables (old value if any, or remove from list)
if (is_array($this->vArgs)) {
foreach ($this->vArgs as $name => $value) {
if (isset($oldVars[$name])) {
W3SetVar($name, $oldVars[$name]);
} else {
W3KillVar($name);
}
}
}
return $out;
}
}
 
class W3TPL_fx {
function runXploop ( &$parser, $inStr = '', $inTplt = '$s$', $inSep = '' )
{
$tok = substr ( $inStr, 0, 1); // token for splitting
if ($tok) {
$tks = substr ( $inStr, 1 ); // tokenized string
$list = explode ( $tok, $tks ); // split the string
$sep = CharacterEscapes::charUnesc( $inSep, array(), $parser );
$tplt = CharacterEscapes::charUnesc( $inTplt, array(), $parser );
$out = '';
foreach ($list as $value) {
// $lcnt++;
if ($out) {
$out .= $sep;
}
$out .= str_replace( '$s$', $value, $tplt );
}
return $parser->recursiveTagParse($out);
// return array($out, 'noparse' => false, 'isHTML' => false);
} else {
return NULL;
}
}
function runXpCount ( &$parser, $inStr = '' )
{
$tok = substr ( $inStr, 0, 1);
return substr_count($inStr, $tok);
}
function runLet ( &$parser, $iName = '', $iVal = '' ) {
global $wgW3Vars;
 
$strName = strtolower($iName);
$strName = W3GetVal($strName); // check for indirection ($)
$wgW3Vars[$strName] .= $iVal;
}
function runGet ( &$parser, $iName = '' ) {
$strName = strtolower($iName);
$strVal = W3GetVal('$'.$strName);
return $parser->recursiveTagParse($strVal);
}
}</php>

Latest revision as of 00:24, 24 April 2022

About

W3TPL, which stands for Woozle's Wacky Wiki Text Processing Language, is a scripting language extension for MediaWiki. It was written to permit some simple scripting and to get around certain restrictions of the wikitext format (e.g. emitting "dangerous" tags). It has largely been superceded by new options and other MediaWiki extensions that are better supported (such as Scribunto), and some tags/options do not currently work.

Pages

  • /recipes: useful snippets for W3TPL
  • /tags: tags defined for use within wikitext
  • /sysdata: syntax for accessing system data
  • /test suite: code to verify that W3TPL is working properly
  • /history: change log
  • /dev: bits & pieces under development
  • /archive: obsolete stuff

Links

  • GitLab: official code repository

Technical Notes

W3TPL gets initialized like this: