|
|
| 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 “'.$strName;
| |
| if ($strName != $strNameRaw) {
| |
| $strTrace .= ' ('.$strNameRaw.')';
| |
| }
| |
| $strTrace .= '” = “'.$strVal.'”';
| |
| 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 “'.$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=[<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 ( '<','<',$iText );
| |
| $out = str_replace ( '>','>',$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>]=“'.$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>
| |