Difference between revisions of "W3TPL"

from HTYP, the free directory anyone can edit if they can prove to me that they're not a spambot
Jump to navigation Jump to search
(→‎Code: 9/5 revision -- working except for w3tpl tag)
(moved source code to separate page; pages section: +recipes (subpage link), +source (subpage link))
Line 1: Line 1:
 
==Overview==
 
==Overview==
 
[[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.
 
[[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.
==Code==
+
===Pages===
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.
+
* [[/recipes]]: useful snippets for W3TPL
 
+
* [[/source]]: the source code for the extension
All the tags except <w3tpl> work, but parser interactions make them problematic for more complex applications.
 
<php><?php
 
/*
 
HISTORY:
 
0.01 (Wzl) Mainly proof-of-concept;
 
parser should later be optimized for execution time by using PHP intrinsic string fx instead of PHP-code loop
 
0.02 (Wzl) Kluge to let <xploop> pull #var value under MW <1.12
 
TO DO: If page is not protected, pre should be forced FALSE and post should be forced TRUE
 
"pre" can do weird things
 
"post" set false allows raw HTML
 
0.03 (Wzl) <func> and related tags seem to be working
 
0.04 (Wzl) Some debugging; now works with v1.12 {{#tag}} function and template parameters (but not very well)
 
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
 
0.10 (Wzl) Code runs ok; still writing <w3tpl> tag
 
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.10 2008-09-05 (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;
 
$idxStack = 0; // reset stack depth
 
$tokens = NULL;
 
$tokType = 0;
 
for ($i = 0; $ch=substr($input,$i,1); $i++) {
 
$doAdd = TRUE; // TRUE = add this character to the token buffer
 
$isTok = FALSE; // TRUE = a token has been completed; save it and clear buffer
 
$isLevel = FALSE; // TRUE = a level has been completed (parens, braces)
 
$inEsc = false; // next character is escaped -- if quote, treat as part of string
 
$doLine = FALSE; // TRUE = line is complete
 
switch ($ch) {
 
  // whitespace
 
  case ' ': // space
 
  case "\t": // tab
 
if (!$inQuo) {
 
$doAdd = false; // don't include unquoted whitespace
 
}
 
break;
 
  case '"':
 
if (!$inEsc) {
 
$inQuo != $inQuo;
 
$isTok = !$inQuo;
 
}
 
break;
 
  case '\\':
 
$inEsc = true;
 
break;
 
  case '(':
 
if (!$inQuo) {
 
$idxStack++;
 
$isTok = TRUE; // start new token
 
$doAdd = false; // don't include paren in token
 
}
 
break;
 
  case ')':
 
if (!$inQuo) {
 
$isTok = TRUE; // start new token
 
$isLevel = TRUE; // close the level
 
$doAdd = FALSE; // don't include parens in token
 
}
 
break;
 
  case '{':
 
if (!$inQuo) {
 
$idxStack++;
 
$isTok = TRUE; // start new token
 
$doAdd = false; // don't include braces in token
 
}
 
break;
 
  case '}':
 
if (!$inQuo) {
 
$isTok = TRUE; // start new token
 
$isLevel = TRUE; // close the level
 
$doAdd = FALSE; // don't include braces in token
 
}
 
break;
 
  case ';':
 
if (!$inQuo) {
 
$isTok = TRUE; // start new token
 
$doAdd = false; // don't include semicolon in token
 
$doLine = TRUE;
 
}
 
break;
 
  case "\n":
 
$doAdd = false; // don't include linebreaks in $clause
 
break;
 
  default:
 
}
 
if ($doAdd) {
 
$token .= $ch;
 
}
 
if ($isTok) { // TRUE = a token has been completed; save it and clear buffer
 
if ($token) {
 
$objTok = new clsW3Token_actual($token);
 
$tokens[$idxStack][] = $objTok;
 
$strDbgLine .= ' '.$token;
 
}
 
$token = NULL;
 
}
 
if ($isLevel) { // TRUE = a level has been completed (parens, braces)
 
$objLine = new clsW3Token_child($tokens[$idxStack]);
 
unset($tokens[$idxStack]);
 
$idxStack--;
 
$tokens[$idxStack][] = $objLine;
 
}
 
if ($doLine) { // TRUE = line is complete
 
//W3AddTrace('TPL: LINE=[<u>'.$strDbgLine.'</u>]');
 
$out .= $cmdObj->execute($lines);
 
}
 
}
 
// final semicolon not required:
 
if ($line) {
 
$out .= $cmdObj->execute($line,$clause);
 
}
 
return $out;
 
}
 
 
 
/*
 
TOKEN TYPES - for future use:
 
() phrase
 
{} brace phrase
 
non-quoted expression
 
quoted string
 
*/
 
abstract class clsW3Token {
 
}
 
class clsW3Token_actual extends clsW3Token {
 
private $vText;
 
 
 
public function __construct($iText) {
 
$this->vText = $iText;
 
}
 
}
 
class clsW3Token_child extends clsW3Token {
 
private $vList;
 
 
 
public function __construct($iList) {
 
$this->vList = $iList;
 
}
 
}
 
/*
 
class clsW3Token_rawexp extends clsW3Token {
 
public __construct($iText) {
 
}
 
}
 
class clsW3Token_qstring extends clsW3Token {
 
public __construct($iText) {
 
}
 
}
 
*/
 
class clsW3ParsedLine {
 
private $tokens;
 
 
 
public function __construct($iTokens) {
 
$this->tokens = $iTokens;
 
}
 
}
 
class clsW3ParsedChunk {
 
private $lines; // array of clsW3ParsedLines
 
 
 
public function __construct($iLines) {
 
$this->lines = $iLines;
 
}
 
}
 
 
 
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>
 

Revision as of 01:32, 12 September 2008

Overview

W3TPL, which stands for 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.

Pages

  • /recipes: useful snippets for W3TPL
  • /source: the source code for the extension