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...)
 
(→‎Code: 9/5 revision -- working except for w3tpl tag)
Line 25: Line 25:
0.08 (Wzl) <trace> to set trace options; "input" option in <call>
0.08 (Wzl) <trace> to set trace options; "input" option in <call>
0.09 (Wzl) <echo> tag; <call> does not output its contents
0.09 (Wzl) <echo> tag; <call> does not output its contents
0.10 (Wzl) Code runs ok; still writing <w3tpl> tag
  BUGS:
  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
$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
Line 44: Line 45:
         'description' => 'Woozle\'s Wacky Wiki Text Processing Language',
         'description' => 'Woozle\'s Wacky Wiki Text Processing Language',
         'author' => 'Woozle (Nick) Staddon',
         'author' => 'Woozle (Nick) Staddon',
'version' => '0.09 2008-08-24 (in progress)'
'version' => '0.10 2008-09-05 (in progress)'
);
);


Line 558: Line 559:
$cmdObj = new clsW3Command();
$cmdObj = new clsW3Command();
$inQuo = FALSE;
$inQuo = FALSE;
$brDepth = 0;
$idxStack = 0; // reset stack depth
$paDepth = 0;
$tokens = NULL;
$line = '';
$tokType = 0;
$clause = '';
for ($i = 0; $ch=substr($input,$i,1); $i++) {
for ($i = 0; $ch=substr($input,$i,1); $i++) {
$isTok = FALSE;
$doAdd = TRUE; // TRUE = add this character to the token buffer
$doAdd = TRUE;
$isTok = FALSE; // TRUE = a token has been completed; save it and clear buffer
$doSave = FALSE;
$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) {
switch ($ch) {
  // whitespace
  // whitespace
Line 571: Line 573:
  case "\t": // tab
  case "\t": // tab
if (!$inQuo) {
if (!$inQuo) {
$isTok = TRUE;
$doAdd = false; // don't include unquoted whitespace
}
}
break;
break;
Line 577: Line 579:
if (!$inEsc) {
if (!$inEsc) {
$inQuo != $inQuo;
$inQuo != $inQuo;
$isTok = !$inQuo;
}
}
break;
break;
Line 584: Line 587:
  case '(':
  case '(':
if (!$inQuo) {
if (!$inQuo) {
$paDepth++;
$idxStack++;
$isTok = TRUE; // start new token
$doAdd = false; // don't include paren in token
}
}
break;
break;
  case ')':
  case ')':
if (!$inQuo) {
if (!$inQuo) {
$paDepth--;
$isTok = TRUE; // start new token
if ($paDepth == 0) {
$isLevel = TRUE; // close the level
$isArgs = TRUE;
$doAdd = FALSE; // don't include parens in token
}
}
}
break;
break;
  case '{':
  case '{':
if (!$inQuo) {
if (!$inQuo) {
$brDepth++;
$idxStack++;
$doAdd = false; // don't include braces in $clause
$isTok = TRUE; // start new token
$doAdd = false; // don't include braces in token
}
}
break;
break;
  case '}':
  case '}':
if (!$inQuo) {
if (!$inQuo) {
$brDepth--;
$isTok = TRUE; // start new token
if ($brDepth == 0) {
$isLevel = TRUE; // close the level
// end of braces is equivalent to semicolon
$doAdd = FALSE; // don't include braces in token
$doSave = true;
$doAdd = false; // don't include braces in $clause
}
}
}
break;
break;
  case ';':
  case ';':
if (!$inQuo) {
if (!$inQuo) {
if ($brDepth == 0) {
$isTok = TRUE; // start new token
$doSave = true;
$doAdd = false; // don't include semicolon in token
$doAdd = false;
$doLine = TRUE;
}
}
}
break;
break;
Line 625: Line 626:
}
}
if ($doAdd) {
if ($doAdd) {
if ($brDepth) {
$token .= $ch;
$clause .= $ch;
}
} else {
if ($isTok) { // TRUE = a token has been completed; save it and clear buffer
$line .= $ch;
if ($token) {
$objTok = new clsW3Token_actual($token);
$tokens[$idxStack][] = $objTok;
$strDbgLine .= ' '.$token;
}
}
$inEsc = false;
$token = NULL;
}
}
if ($doSave) {
if ($isLevel) { // TRUE = a level has been completed (parens, braces)
W3AddTrace('TPL: LINE=[<u>'.$line.'</u>] CLAUSE=[<u>'.$clause.'</u>]');
$objLine = new clsW3Token_child($tokens[$idxStack]);
$out .= $cmdObj->execute($line,$clause);
unset($tokens[$idxStack]);
$line = '';
$idxStack--;
$clause = '';
$tokens[$idxStack][] = $objLine;
$doSave = false;
}
if ($doLine) { // TRUE = line is complete
//W3AddTrace('TPL: LINE=[<u>'.$strDbgLine.'</u>]');
$out .= $cmdObj->execute($lines);
}
}
}
}
Line 645: Line 652:
}
}
return $out;
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;
}
}
}


Line 688: Line 743:
$isArgs = FALSE;
$isArgs = FALSE;
if ($isTok) {
if ($isTok) {
if (!$inQuo) {
//if (!$inQuo) {
if ($cmd == '') {
if ($cmd == '') {
$cmd = $phrase;
$cmd = $phrase;

Revision as of 19:55, 5 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.

Code

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.

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 “'.$strName; if ($strName != $strNameRaw) { $strTrace .= ' ('.$strNameRaw.')'; } $strTrace .= '” = “'.$strVal.'”'; if ($strCopy) { $strTrace .= ' copied from '.$strCopy.''; } 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 = '

    '; if (is_array($wgW3Vars)) { $out .= '
  • Variables:
      '; foreach ($wgW3Vars as $name => $value) { $out .= '
    • ['.$name.'] = ['.$value.']'; } $out .= '
    ';

    } else {

    $out .= '
  • No variables set'; } if (is_array($wgW3_funcs)) { $out .= '
  • Functions:
      '; foreach ($wgW3_funcs as $name => $obj) { $out .= '
    • '.$obj->dump(); } $out .= '
    ';

    } else {

    $out .= '
  • No functions defined'; } if (isset($args['trace'])) { if (is_array($wgW3Trace)) { $out .= '
  • Trace:
      '; foreach ($wgW3Trace as $idx => $line) { $indLine = $wgW3Trace_indents[$idx]; if ($indLine > $indCur) { $out .= '
        '; } elseif ($indLine < $indCur) { $out .= '
      ';

      } $indCur = $indLine;

      $out .= '
    • '.$idx.' '.$line; } $out .= '
    ';

    } else {

    $out .= '
  • No trace events'; } } $out .= '

';

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 “'.$funcName.'”'); $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).') <= “'.ShowHTML($strList).'”'; } else { // setting variable value $strTrace = 'XPLOOP set ('.ShowHTML($strVar).') <= “'.ShowHTML($strList).'”'; } if ($strList != $strListRaw) { $strTrace .= '<=“'.$strListRaw.'”'; } 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=['.$strDbgLine.']'); $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 = '
CMD: {'.$strStmt.'} CLAUSE: {'.$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=['.$cmd.'] ARGS=['.$args.'] leftover=['.$phrase.']'); // return $out; } }

function ShowHTML($iText) { $out = str_replace ( '<','<',$iText ); $out = str_replace ( '>','>',$out); $out = str_replace ( chr(7),'^G',$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 = ''.$this->vName.'('; if (is_array($this->vParams)) { foreach ($this->vParams as $name => $value) { if ($pcnt) { $out .= ', '; } $out .= ''.$name.''; if (isset($value)) { $out .= '='.$value; } $pcnt++; } } $out .= ') {'; $strCode = ShowHTML($this->vCode);

$out .= '

'.$strCode.'

}';

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 '['.$strName.']=“'.$iValue.'”'; } 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>