From 33d102d674ca3c0ef35575d5d63350a22368f674 Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Wed, 9 Feb 2011 16:53:59 +1300 Subject: [PATCH 01/15] ENHANCEMENT: Piston in php-peg library --- thirdparty/php-peg/.piston.yml | 9 + thirdparty/php-peg/Compiler.php | 783 ++++++++++++++++++ thirdparty/php-peg/LICENSE | 10 + thirdparty/php-peg/PHPBuilder.php | 127 +++ thirdparty/php-peg/Parser.php | 323 ++++++++ thirdparty/php-peg/README.md | 230 +++++ thirdparty/php-peg/cli.php | 5 + .../examples/CalculatedLiterals.peg.inc | 25 + .../php-peg/examples/Calculator.peg.inc | 63 ++ .../php-peg/examples/EqualRepeat.peg.inc | 36 + thirdparty/php-peg/examples/Rfc822.peg.inc | 88 ++ .../php-peg/examples/Rfc822UTF8.peg.inc | 30 + 12 files changed, 1729 insertions(+) create mode 100644 thirdparty/php-peg/.piston.yml create mode 100644 thirdparty/php-peg/Compiler.php create mode 100644 thirdparty/php-peg/LICENSE create mode 100644 thirdparty/php-peg/PHPBuilder.php create mode 100644 thirdparty/php-peg/Parser.php create mode 100644 thirdparty/php-peg/README.md create mode 100644 thirdparty/php-peg/cli.php create mode 100644 thirdparty/php-peg/examples/CalculatedLiterals.peg.inc create mode 100644 thirdparty/php-peg/examples/Calculator.peg.inc create mode 100644 thirdparty/php-peg/examples/EqualRepeat.peg.inc create mode 100644 thirdparty/php-peg/examples/Rfc822.peg.inc create mode 100644 thirdparty/php-peg/examples/Rfc822UTF8.peg.inc diff --git a/thirdparty/php-peg/.piston.yml b/thirdparty/php-peg/.piston.yml new file mode 100644 index 000000000..0ecfabf6b --- /dev/null +++ b/thirdparty/php-peg/.piston.yml @@ -0,0 +1,9 @@ +--- +format: 1 +handler: + commit: afb28caf712815da82cd6bb8ece8ac12ab9b2188 + branch: master +lock: false +repository_class: Piston::Git::Repository +repository_url: git://github.com/hafriedlander/php-peg.git +exported_to: 0669b742904f8c9f7cd97569166663396897dab9 diff --git a/thirdparty/php-peg/Compiler.php b/thirdparty/php-peg/Compiler.php new file mode 100644 index 000000000..2acd72dae --- /dev/null +++ b/thirdparty/php-peg/Compiler.php @@ -0,0 +1,783 @@ +parent = $parent ; + $this->flags = array() ; + } + + function __set( $k, $v ) { + $this->flags[$k] = $v ; + return $v ; + } + + function __get( $k ) { + if ( isset( $this->flags[$k] ) ) return $this->flags[$k] ; + if ( isset( $this->parent ) ) return $this->parent->$k ; + return NULL ; + } +} + +/** + * PHPWriter contains several code generation snippets that are used both by the Token and the Rule compiler + */ +class PHPWriter { + + static $varid = 0 ; + + function varid() { + return '_' . (self::$varid++) ; + } + + function function_name( $str ) { + $str = preg_replace( '/-/', '_', $str ) ; + $str = preg_replace( '/\$/', 'DLR', $str ) ; + $str = preg_replace( '/\*/', 'STR', $str ) ; + $str = preg_replace( '/[^\w]+/', '', $str ) ; + return $str ; + } + + function save($id) { + return PHPBuilder::build() + ->l( + '$res'.$id.' = $result;', + '$pos'.$id.' = $this->pos;' + ); + } + + function restore( $id, $remove = FALSE ) { + $code = PHPBuilder::build() + ->l( + '$result = $res'.$id.';', + '$this->pos = $pos'.$id.';' + ); + + if ( $remove ) $code->l( + 'unset( $res'.$id.' );', + 'unset( $pos'.$id.' );' + ); + + return $code ; + } + + function match_fail_conditional( $on, $match = NULL, $fail = NULL ) { + return PHPBuilder::build() + ->b( 'if (' . $on . ')', + $match, + 'MATCH' + ) + ->b( 'else', + $fail, + 'FAIL' + ); + } + + function match_fail_block( $code ) { + $id = $this->varid() ; + + return PHPBuilder::build() + ->l( + '$'.$id.' = NULL;' + ) + ->b( 'do', + $code->replace(array( + 'MBREAK' => '$'.$id.' = TRUE; break;', + 'FBREAK' => '$'.$id.' = FALSE; break;' + )) + ) + ->l( + 'while(0);' + ) + ->b( 'if( $'.$id.' === TRUE )', 'MATCH' ) + ->b( 'if( $'.$id.' === FALSE)', 'FAIL' ) + ; + } +} + +/** + * A Token is any portion of a match rule. Tokens are responsible for generating the code to match against them. + * + * This base class provides the compile() function, which handles the token modifiers ( ? * + & ! ) + * + * Each child class should provide the function match_code() which will generate the code to match against that specific token type. + * In that generated code they should include the lines MATCH or FAIL when a match or a decisive failure occurs. These will + * be overwritten when they are injected into parent Tokens or Rules. There is no requirement on where MATCH and FAIL can occur. + * They tokens are also responsible for storing and restoring state when nessecary to handle a non-decisive failure. + * + * @author hamish + * + */ +abstract class Token extends PHPWriter { + public $optional = FALSE ; + public $zero_or_more = FALSE ; + public $one_or_more = FALSE ; + public $positive_lookahead = FALSE ; + public $negative_lookahead = FALSE ; + public $silent = FALSE ; + + public $tag = FALSE ; + + public $type ; + public $value ; + + function __construct( $type, $value = NULL ) { + $this->type = $type ; + $this->value = $value ; + } + + // abstract protected function match_code() ; + + function compile() { + $code = $this->match_code() ; + + $id = $this->varid() ; + + if ( $this->optional ) { + $code = PHPBuilder::build() + ->l( + $this->save($id), + $code->replace( array( 'FAIL' => $this->restore($id,true) )) + ); + } + + if ( $this->zero_or_more ) { + $code = PHPBuilder::build() + ->b( 'while (true)', + $this->save($id), + $code->replace( array( + 'MATCH' => NULL, + 'FAIL' => + $this->restore($id,true) + ->l( 'break;' ) + )) + ) + ->l( + 'MATCH' + ); + } + + if ( $this->one_or_more ) { + $code = PHPBuilder::build() + ->l( + '$count = 0;' + ) + ->b( 'while (true)', + $this->save($id), + $code->replace( array( + 'MATCH' => NULL, + 'FAIL' => + $this->restore($id,true) + ->l( 'break;' ) + )), + '$count += 1;' + ) + ->b( 'if ($count > 0)', 'MATCH' ) + ->b( 'else', 'FAIL' ); + } + + if ( $this->positive_lookahead ) { + $code = PHPBuilder::build() + ->l( + $this->save($id), + $code->replace( array( + 'MATCH' => + $this->restore($id) + ->l( 'MATCH' ), + 'FAIL' => + $this->restore($id) + ->l( 'FAIL' ) + ))); + } + + if ( $this->negative_lookahead ) { + $code = PHPBuilder::build() + ->l( + $this->save($id), + $code->replace( array( + 'MATCH' => + $this->restore($id) + ->l( 'FAIL' ), + 'FAIL' => + $this->restore($id) + ->l( 'MATCH' ) + ))); + } + + if ( $this->tag && !($this instanceof TokenRecurse ) ) { + $rid = $this->varid() ; + $code = PHPBuilder::build() + ->l( + '$substack[] = $result;', + '$result = $this->construct( "'.$this->tag.'" );', + $code->replace(array( + 'MATCH' => PHPBuilder::build() + ->l( + '$subres = $result ;', + '$result = array_pop( $substack ) ;', + '$this->store( $result, $subres, \''.$this->tag.'\' );', + 'MATCH' + ), + 'FAIL' => PHPBuilder::build() + ->l( + '$result = array_pop( $substack ) ;', + 'FAIL' + ) + ))); + } + + return $code ; + } + +} + +abstract class TokenTerminal extends Token { + function set_text( $text ) { + return $this->silent ? NULL : '$result["text"] .= ' . $text . ';'; + } + + protected function match_code( $value ) { + return $this->match_fail_conditional( '( $subres = $this->'.$this->type.'( '.$value.' ) ) !== FALSE', + $this->set_text('$subres') + ); + } +} + +abstract class TokenExpressionable extends TokenTerminal { + + static $expression_rx = '/\$(\w+)/' ; + + function contains_expression(){ + return preg_match(self::$expression_rx, $this->value); + } + + function match_code( $value ) { + if (!$this->contains_expression()) parent::match_code($value); + + $id = $this->varid() ; + return PHPBuilder::build()->l( + '$'.$id.' = new ParserExpression( $this, $substack, $result );', + parent::match_code('$'.$id.'->expand('.$value.')') + ); + } +} + +class TokenLiteral extends TokenExpressionable { + function __construct( $value ) { + parent::__construct( 'literal', $value ); + } + + function match_code() { + // We inline single-character matches for speed + if ( strlen( eval( 'return '. $this->value . ';' ) ) == 1 ) { + return $this->match_fail_conditional( 'substr($this->string,$this->pos,1) == '.$this->value, + PHPBuilder::build()->l( + '$this->pos += 1;', + $this->set_text( $this->value ) + ) + ); + } + return parent::match_code($this->value); + } +} + +class TokenRegex extends TokenExpressionable { + static function escape( $rx ) { + $rx = str_replace( "'", "\\'", $rx ) ; + $rx = str_replace( '\\\\', '\\\\\\\\', $rx ) ; + return $rx ; + } + + function __construct( $value ) { + parent::__construct('rx', self::escape($value)); + } + + function match_code() { + return parent::match_code("'{$this->value}'"); + } +} + +class TokenWhitespace extends TokenTerminal { + function __construct( $optional ) { + parent::__construct( 'whitespace', $optional ) ; + } + + /* Call recursion indirectly */ + function match_code() { + $code = parent::match_code( '' ) ; + return $this->value ? $code->replace( array( 'FAIL' => NULL )) : $code ; + } +} + +class TokenPHP extends TokenTerminal { + function __construct( $value ) { + parent::__construct( 'php', $value ) ; + } + + /* Call recursion indirectly */ + function match_code() { + $id = $this->varid() ; + return PHPBuilder::build() + ->l( + '$'.$id.' = new ParserExpression( $this, $substack, $result );', + $this->match_fail_block( '( $subres = $'.$id.'->match( \''.$this->value.'\' ) ) !== FALSE', + PHPBuilder::build() + ->b( 'if ( is_string( $subres ) )', + $this->set_text('$subres') + ) + ->b( 'else', + '$this->store($result, $subres);' + ) + )); + } +} + +class TokenRecurse extends Token { + function __construct( $value ) { + parent::__construct( 'recurse', $value ) ; + } + + function match_code() { + $function = $this->function_name( $this->value ) ; + $storetag = $this->function_name( $this->tag ? $this->tag : $this->value ) ; + + if ( ParserCompiler::$debug ) { + $debug_header = PHPBuilder::build() + ->l( + '$indent = str_repeat( " ", $this->depth );', + '$this->depth += 2;', + '$sub = ( strlen( $this->string ) - $this->pos > 20 ) ? ( substr( $this->string, $this->pos, 20 ) . "..." ) : substr( $this->string, $this->pos );', + '$sub = preg_replace( \'/(\r|\n)+/\', " {NL} ", $sub );', + 'print( $indent."Matching against '.$function.' (".$sub.")\n" );' + ); + + $debug_match = PHPBuilder::build() + ->l( + 'print( $indent."MATCH\n" );', + '$this->depth -= 2;' + ); + + $debug_fail = PHPBuilder::build() + ->l( + 'print( $indent."FAIL\n" );', + '$this->depth -= 2;' + ); + } + else { + $debug_header = $debug_match = $debug_fail = NULL ; + } + + return PHPBuilder::build()->l( + $debug_header, + '$key = "'.$function.'"; $pos = $this->pos;', // :{$this->pos}";', + '$subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_'.$function.'(array_merge($substack, array($result))) ) );', + $this->match_fail_conditional( '$subres !== FALSE', + PHPBuilder::build()->l( + $debug_match, + $this->tag === FALSE ? + '$this->store( $result, $subres );' : + '$this->store( $result, $subres, "'.$storetag.'" );' + ), + PHPBuilder::build()->l( + $debug_fail + ) + )); + } +} + +class TokenSequence extends Token { + function __construct( $value ) { + parent::__construct( 'sequence', $value ) ; + } + + function match_code() { + $code = PHPBuilder::build() ; + foreach( $this->value as $token ) { + $code->l( + $token->compile()->replace(array( + 'MATCH' => NULL, + 'FAIL' => 'FBREAK' + )) + ); + } + $code->l( 'MBREAK' ); + + return $this->match_fail_block( $code ) ; + } +} + +class TokenOption extends Token { + function __construct( $opt1, $opt2 ) { + parent::__construct( 'option', array( $opt1, $opt2 ) ) ; + } + + function match_code() { + $id = $this->varid() ; + $code = PHPBuilder::build() + ->l( + $this->save($id) + ) ; + + foreach ( $this->value as $opt ) { + $code->l( + $opt->compile()->replace(array( + 'MATCH' => 'MBREAK', + 'FAIL' => NULL + )), + $this->restore($id) + ); + } + $code->l( 'FBREAK' ) ; + + return $this->match_fail_block( $code ) ; + } +} + + +/** + * Handles storing of information for an expression that applys to the next token, and deletion of that + * information after applying + * + * @author Hamish Friedlander + */ +class Pending { + function __construct() { + $this->what = NULL ; + } + + function set( $what, $val = TRUE ) { + $this->what = $what ; + $this->val = $val ; + } + + function apply_if_present( $on ) { + if ( $this->what !== NULL ) { + $what = $this->what ; + $on->$what = $this->val ; + + $this->what = NULL ; + } + } +} + +/** + * Rule parsing and code generation + * + * A rule is the basic unit of a PEG. This parses one rule, and generates a function that will match on a string + * + * @author Hamish Friedlander + */ +class Rule extends PHPWriter { + + static $rule_rx = '@^[\x20\t]+(.*)@' ; + static $func_rx = '@^[\x20\t]+function\s+([^\s(]+)\s*\(([^)]*)\)@' ; + + function __construct( $indent, $rules, $match ) { + $this->indent = $indent; + $this->name = $match[1][0] ; + $this->rule = $match[2][0] ; + $this->functions = array() ; + + $active_function = NULL ; + + /* Find all the lines following the rule start which are indented */ + $offset = $match[0][1] + strlen( $match[0][0] ) ; + $lines = preg_split( '/\r\n|\r|\n/', substr( $rules, $offset ) ) ; + + $rule_rx = '@^'.preg_quote($indent).'[\x20\t]+(.*)@' ; + $func_rx = '@^'.preg_quote($indent).'[\x20\t]+function\s+([^\s(]+)\s*\(([^)]*)\)@' ; + + foreach( $lines as $line ) { + if ( !trim( $line ) ) continue ; + if ( !preg_match( $rule_rx, $line, $match ) ) break ; + + /* Handle function definitions */ + if ( preg_match( $func_rx, $line, $func_match, 0 ) ) { + $active_function = $func_match[1] ; + $this->functions[$active_function] = array( $func_match[2], "" ) ; + } + else { + if ( $active_function ) $this->functions[$active_function][1] .= $line . PHP_EOL ; + else $this->rule .= PHP_EOL . trim($line) ; + } + } + + $this->parse_rule() ; + } + + /* Manual parsing, because we can't bootstrap ourselves yet */ + function parse_rule() { + $rule = trim( $this->rule ) ; + + /* If this is a regex end-token, just mark it and return */ + if ( substr( $rule, 0, 1 ) == '/' ) { + $this->parsed = new TokenRegex( $rule ) ; + } + else { + $tokens = array() ; + $this->tokenize( $rule, $tokens ) ; + $this->parsed = ( count( $tokens ) == 1 ? array_pop( $tokens ) : new TokenSequence( $tokens ) ) ; + } + } + + static $rx_rx = '{^/( + ((\\\\\\\\)*\\\\/) # Escaped \/, making sure to catch all the \\ first, so that we dont think \\/ is an escaped / + | + [^/] # Anything except / + )*/}xu' ; + + function tokenize( $str, &$tokens, $o = 0 ) { + + $pending = new Pending() ; + + while ( $o < strlen( $str ) ) { + $sub = substr( $str, $o ) ; + + /* Absorb white-space */ + if ( preg_match( '/^\s+/', $sub, $match ) ) { + $o += strlen( $match[0] ) ; + } + /* Handle expression labels */ + elseif ( preg_match( '/^(\w*):/', $sub, $match ) ) { + $pending->set( 'tag', isset( $match[1] ) ? $match[1] : '' ) ; + $o += strlen( $match[0] ) ; + } + /* Handle descent token */ + elseif ( preg_match( '/^[\w-]+/', $sub, $match ) ) { + $tokens[] = $t = new TokenRecurse( $match[0] ) ; $pending->apply_if_present( $t ) ; + $o += strlen( $match[0] ) ; + } + /* Handle " quoted literals */ + elseif ( preg_match( '/^"[^"]*"/', $sub, $match ) ) { + $tokens[] = $t = new TokenLiteral( $match[0] ) ; $pending->apply_if_present( $t ) ; + $o += strlen( $match[0] ) ; + } + /* Handle ' quoted literals */ + elseif ( preg_match( "/^'[^']*'/", $sub, $match ) ) { + $tokens[] = $t = new TokenLiteral( $match[0] ) ; $pending->apply_if_present( $t ) ; + $o += strlen( $match[0] ) ; + } + /* Handle regexs */ + elseif ( preg_match( self::$rx_rx, $sub, $match ) ) { + $tokens[] = $t = new TokenRegex( $match[0] ) ; $pending->apply_if_present( $t ) ; + $o += strlen( $match[0] ) ; + } + /* Handle $ call literals */ + elseif ( preg_match( '/^\$(\w+)/', $sub, $match ) ) { + $tokens[] = $t = new TokenPHP( $match[1] ) ; $pending->apply_if_present( $t ) ; + $o += strlen( $match[0] ) ; + } + /* Handle flags */ + elseif ( preg_match( '/^\@(\w+)/', $sub, $match ) ) { + $l = count( $tokens ) - 1 ; + $o += strlen( $match[0] ) ; + user_error( "TODO: Flags not currently supported", E_USER_WARNING ) ; + } + /* Handle control tokens */ + else { + $c = substr( $sub, 0, 1 ) ; + $l = count( $tokens ) - 1 ; + $o += 1 ; + switch( $c ) { + case '?': + $tokens[$l]->optional = TRUE ; + break ; + case '*': + $tokens[$l]->zero_or_more = TRUE ; + break ; + case '+': + $tokens[$l]->one_or_more = TRUE ; + break ; + + case '&': + $pending->set( 'positive_lookahead' ) ; + break ; + case '!': + $pending->set( 'negative_lookahead' ) ; + break ; + + case '.': + $pending->set( 'silent' ); + break; + + case '[': + case ']': + $tokens[] = new TokenWhitespace( FALSE ) ; + break ; + case '<': + case '>': + $tokens[] = new TokenWhitespace( TRUE ) ; + break ; + + case '(': + $subtokens = array() ; + $o = $this->tokenize( $str, $subtokens, $o ) ; + $tokens[] = $t = new TokenSequence( $subtokens ) ; $pending->apply_if_present( $t ) ; + break ; + case ')': + return $o ; + + case '|': + $option1 = $tokens ; + $option2 = array() ; + $o = $this->tokenize( $str, $option2, $o ) ; + + $option1 = (count($option1) == 1) ? $option1[0] : new TokenSequence( $option1 ); + $option2 = (count($option2) == 1) ? $option2[0] : new TokenSequence( $option2 ); + + $pending->apply_if_present( $option2 ) ; + + $tokens = array( new TokenOption( $option1, $option2 ) ) ; + return $o ; + + default: + user_error( "Can't parser $c - attempting to skip", E_USER_WARNING ) ; + } + } + } + + return $o ; + } + + /** + * Generate the PHP code for a function to match against a string for this rule + */ + function compile() { + $function_name = $this->function_name( $this->name ) ; + + $match = PHPBuilder::build() ; + + if ( $this->parsed instanceof TokenRegex ) { + $match->b( "function match_{$function_name} (\$substack = array())", + '$result = array("name"=>"'.$function_name.'", "text"=>"");', + $this->parsed->compile()->replace(array( + 'MATCH' => 'return $result;', + 'FAIL' => 'return FALSE;' + )) + ); + } + else { + $match->b( "function match_{$function_name} (\$substack = array())", + '$result = $this->construct( "'.$function_name.'" );', + $this->parsed->compile()->replace(array( + 'MATCH' => 'return $this->finalise( "'.$function_name.'", $result );', + 'FAIL' => 'return FALSE;' + )) + ); + } + + $functions = array() ; + foreach( $this->functions as $name => $function ) { + $function_name = $this->function_name( preg_match( '/^_/', $name ) ? $this->name.$name : $this->name.'_'.$name ) ; + $functions[] = implode( PHP_EOL, array( + 'function ' . $function_name . ' ( ' . $function[0] . ' ) { ', + $function[1], + )); + } + + // print_r( $match ) ; return '' ; + return $match->render(NULL, $this->indent) . PHP_EOL . PHP_EOL . implode( PHP_EOL, $functions ) ; + } +} + +class ParserCompiler { + + static $debug = false; + + static $currentClass = null; + + static function create_parser( $match ) { + /* We allow indenting of the whole rule block, but only to the level of the comment start's indent */ + $indent = $match[1]; + + /* The regex to match a rule */ + $rx = '@^'.preg_quote($indent).'([\w\-]+):(.*)$@m' ; + + /* Class isn't actually used ATM. Eventually it might be used for rule inlineing optimization */ + if ($class = trim($match[2])) self::$currentClass = $class; + elseif (self::$currentClass) $class = self::$currentClass; + else $class = self::$currentClass = 'Anonymous Parser'; + + /* Get the actual body of the parser rule set */ + $rulestr = $match[3] ; + + /* Check for pragmas */ + if (strpos($class, '!') === 0) { + switch ($class) { + case '!silent': + // NOP - dont output + return ''; + case '!insert_autogen_warning': + return $ident . implode(PHP_EOL.$ident, array( + '/*', + 'WARNING: This file has been machine generated. Do not edit it, or your changes will be overwritten next time it is compiled.', + '*/' + )) . PHP_EOL; + case '!debug': + self::$debug = true; + return ''; + } + + throw new Exception("Unknown pragma $class encountered when compiling parser"); + } + + $rules = array(); + + preg_match_all( $rx, $rulestr, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE ) ; + foreach ( $matches as $match ) { + $rules[] = new Rule( $indent, $rulestr, $match ) ; + } + + $out = array() ; + + foreach ( $rules as $rule ) { + $out[] = $indent . '/* ' . $rule->name . ':' . $rule->rule . ' */' . PHP_EOL ; + $out[] = $rule->compile() ; + $out[] = PHP_EOL ; + } + + return implode( '', $out ) ; + } + + static function compile( $string ) { + static $rx = '@ + ^([\x20\t]*)/\*!\* (?:[\x20\t]*(!?\w*))? # Start with some indent, a comment with the special marker, then an optional name + ((?:[^*]|\*[^/])*) # Any amount of "a character that isnt a star, or a star not followed by a / + \*/ # The comment end + @mx'; + + return preg_replace_callback( $rx, array( 'ParserCompiler', 'create_parser' ), $string ) ; + } + + static function cli( $args ) { + if ( count( $args ) == 1 ) { + print "Parser Compiler: A compiler for PEG parsers in PHP \n" ; + print "(C) 2009 SilverStripe. See COPYING for redistribution rights. \n" ; + print "\n" ; + print "Usage: {$args[0]} infile [ outfile ]\n" ; + print "\n" ; + } + else { + $fname = ( $args[1] == '-' ? 'php://stdin' : $args[1] ) ; + $string = file_get_contents( $fname ) ; + $string = self::compile( $string ) ; + + if ( !empty( $args[2] ) && $args[2] != '-' ) { + file_put_contents( $args[2], $string ) ; + } + else { + print $string ; + } + } + } +} diff --git a/thirdparty/php-peg/LICENSE b/thirdparty/php-peg/LICENSE new file mode 100644 index 000000000..d5841d826 --- /dev/null +++ b/thirdparty/php-peg/LICENSE @@ -0,0 +1,10 @@ +Copyright (C) 2009 Hamish Friedlander (hamish@silverstripe.com) and SilverStripe Limited (www.silverstripe.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of Hamish Friedlander nor SilverStripe nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/thirdparty/php-peg/PHPBuilder.php b/thirdparty/php-peg/PHPBuilder.php new file mode 100644 index 000000000..65206826e --- /dev/null +++ b/thirdparty/php-peg/PHPBuilder.php @@ -0,0 +1,127 @@ +lines = array() ; + } + + function l() { + foreach ( func_get_args() as $lines ) { + if ( !$lines ) continue ; + + if ( is_string( $lines ) ) $lines = preg_split( '/\r\n|\r|\n/', $lines ) ; + if ( !$lines ) continue ; + + if ( $lines instanceof PHPBuilder ) $lines = $lines->lines ; + else $lines = array_map( 'ltrim', $lines ) ; + if ( !$lines ) continue ; + + $this->lines = array_merge( $this->lines, $lines ) ; + } + return $this ; + } + + function b() { + $args = func_get_args() ; + $entry = array_shift( $args ) ; + + $block = new PHPBuilder() ; + call_user_func_array( array( $block, 'l' ), $args ) ; + + $this->lines[] = array( $entry, $block->lines ) ; + + return $this ; + } + + function replace( $replacements, &$array = NULL ) { + if ( $array === NULL ) { + unset( $array ) ; + $array =& $this->lines ; + } + + $i = 0 ; + while ( $i < count( $array ) ) { + + /* Recurse into blocks */ + if ( is_array( $array[$i] ) ) { + $this->replace( $replacements, $array[$i][1] ) ; + + if ( count( $array[$i][1] ) == 0 ) { + $nextelse = isset( $array[$i+1] ) && is_array( $array[$i+1] ) && preg_match( '/^\s*else\s*$/i', $array[$i+1][0] ) ; + + $delete = preg_match( '/^\s*else\s*$/i', $array[$i][0] ) ; + $delete = $delete || ( preg_match( '/^\s*if\s*\(/i', $array[$i][0] ) && !$nextelse ) ; + + if ( $delete ) { + // Is this always safe? Not if the expression has side-effects. + // print "/* REMOVING EMPTY BLOCK: " . $array[$i][0] . "*/\n" ; + array_splice( $array, $i, 1 ) ; + continue ; + } + } + } + + /* Handle replacing lines with NULL to remove, or string, array of strings or PHPBuilder to replace */ + else { + if ( array_key_exists( $array[$i], $replacements ) ) { + $rep = $replacements[$array[$i]] ; + + if ( $rep === NULL ) { + array_splice( $array, $i, 1 ) ; + continue ; + } + + if ( is_string( $rep ) ) { + $array[$i] = $rep ; + $i++ ; + continue ; + } + + if ( $rep instanceof PHPBuilder ) $rep = $rep->lines ; + + if ( is_array( $rep ) ) { + array_splice( $array, $i, 1, $rep ) ; $i += count( $rep ) + 1 ; + continue ; + } + + throw 'Unknown type passed to PHPBuilder#replace' ; + } + } + + $i++ ; + } + + return $this ; + } + + function render( $array = NULL, $indent = "" ) { + if ( $array === NULL ) $array = $this->lines ; + + $out = array() ; + foreach( $array as $line ) { + if ( is_array( $line ) ) { + list( $entry, $block ) = $line ; + $str = $this->render( $block, $indent . "\t" ) ; + + if ( strlen( $str ) < 40 ) { + $out[] = $indent . $entry . ' { ' . ltrim( $str ) . ' }' ; + } + else { + $out[] = $indent . $entry . ' {' ; + $out[] = $str ; + $out[] = $indent . '}' ; + } + } + else { + $out[] = $indent . $line ; + } + } + + return implode( PHP_EOL, $out ) ; + } +} diff --git a/thirdparty/php-peg/Parser.php b/thirdparty/php-peg/Parser.php new file mode 100644 index 000000000..acae096c8 --- /dev/null +++ b/thirdparty/php-peg/Parser.php @@ -0,0 +1,323 @@ +parser = $parser ; + $this->substack = $substack ; + $this->result = $result ; + } + + function find( $exp ) { + $rule_callback = array( $this->parser, "{$this->result['name']}_DLR{$exp}" ) ; + $pars_callback = array( $this->parser, "DLR{$exp}" ) ; + + /* If the current result has that expression, return it */ + if ( isset( $this->result[$exp] ) ) return $this->result[$exp] ; + + /* Search backwards through the sub-expression stacks */ + for ( $i = count( $this->substack ) - 1 ; $i >= 0 ; $i-- ) { + if ( isset( $this->substack[$i][$exp] ) ) return $this->substack[$i][$exp] ; + } + + /* If we have a rule-attached method, call that */ + if ( is_callable( $rule_callback ) ) return call_user_func( $rule_callback, $result ) ; + + /* If we have a class-wide method, call that */ + if ( is_callable( $pars_callback ) ) return call_user_func( $pars_callback, $result ) ; + + /* If we have a global function, call that */ + if ( function_exists( $exp ) ) return call_user_func( $exp, $result ) ; + + /* If we have a global constant, call that */ + if ( defined( $exp ) ) return constant( $expression ) ; + + return FALSE ; + } + + function callback( $m ) { + $res = $this->find( $m[1] ) ; + if ( $res === FALSE ) return "" ; + if ( is_string( $res ) ) return $res ; + if ( isset( $res['text'] ) ) return $res['text'] ; + + // If we find no matches, assume we don't want a replacement, and replace it with itself + return $m[0] ; + } + + function expand( $var ) { + return preg_replace_callback( '/\$(\w+)/', array( $this, 'callback' ), $var ) ; + } + + function match( $var ) { + return $this->find( $var ) ; + } +} + +/** + * We cache the last regex result. This is a low-cost optimization, because we have to do an un-anchored match + check match position anyway + * (alternative is to do an anchored match on a string cut with substr, but that is very slow for long strings). We then don't need to recheck + * for any position between current position and eventual match position - result will be the same + * + * Of course, the next regex might be outside that bracket - after the bracket if other matches have progressed beyond the match position, or before + * the bracket if a failed match + restore has moved the current position backwards - so we have to check that too. + */ +class ParserRegexp { + function __construct( $parser, $rx ) { + $this->parser = $parser ; + $this->rx = $rx . 'Sx' ; + + $this->matches = NULL ; + $this->match_pos = NULL ; // NULL is no-match-to-end-of-string, unless check_pos also == NULL, in which case means undefined + $this->check_pos = NULL ; + } + + function match() { + $current_pos = $this->parser->pos ; + $dirty = $this->check_pos === NULL || $this->check_pos > $current_pos || ( $this->match_pos !== NULL && $this->match_pos < $current_pos ) ; + + if ( $dirty ) { + $this->check_pos = $current_pos ; + $matched = preg_match( $this->rx, $this->parser->string, $this->matches, PREG_OFFSET_CAPTURE, $this->check_pos) ; + if ( $matched ) $this->match_pos = $this->matches[0][1] ; else $this->match_pos = NULL ; + } + + if ( $this->match_pos === $current_pos ) { + $this->parser->pos += strlen( $this->matches[0][0] ); + return $this->matches[0][0] ; + } + + return FALSE ; + } +} + +/** + * Parser base class + * - handles current position in string + * - handles matching that position against literal or rx + * - some abstraction of code that would otherwise be repeated many times in a compiled grammer, mostly related to calling user functions + * for result construction and building + */ +class Parser { + function __construct( $string ) { + $this->string = $string ; + $this->pos = 0 ; + + $this->depth = 0 ; + + $this->regexps = array() ; + } + + function whitespace() { + $matched = preg_match( '/[ \t]+/', $this->string, $matches, PREG_OFFSET_CAPTURE, $this->pos ) ; + if ( $matched && $matches[0][1] == $this->pos ) { + $this->pos += strlen( $matches[0][0] ); + return ' ' ; + } + return FALSE ; + } + + function literal( $token ) { + /* Debugging: * / print( "Looking for token '$token' @ '" . substr( $this->string, $this->pos ) . "'\n" ) ; /* */ + $toklen = strlen( $token ) ; + $substr = substr( $this->string, $this->pos, $toklen ) ; + if ( $substr == $token ) { + $this->pos += $toklen ; + return $token ; + } + return FALSE ; + } + + function rx( $rx ) { + if ( !isset( $this->regexps[$rx] ) ) $this->regexps[$rx] = new ParserRegexp( $this, $rx ) ; + return $this->regexps[$rx]->match() ; + } + + function expand( $var, $substack, $result ) { + $cb = new Parser_ExpressionCallback( $this, $substack, $result ) ; + $v = preg_replace_callback( '/\$(\w+)/', array( $cb, 'callback' ), $var ) ; + print "Expanded var: $v" ; + return $v ; + } + + function php( $var, $substack, $result ) { + $ex = $this->get_expression( $var, $substack, $result ) ; + print_r( $result ) ; + + if ( is_string( $ex ) ) { + return ( preg_match( '{^\s*/}', $ex ) ? $this->rx( $ex ) : $this->literal( $ex ) ) ; + } + return $ex ; + } + + function packhas( $key, $pos ) { + return false ; + } + + function packread( $key, $pos ) { + throw 'PackRead after PackHas=>false in Parser.php' ; + } + + function packwrite( $key, $pos, $res ) { + return $res ; + } + + function construct( $name ) { + $result = array( 'type' => 'node', 'name' => $name, 'text' => '' ) ; + + $callback = array( $this, "{$name}__construct" ) ; + if ( is_callable( $callback ) ) { + call_user_func_array( $callback, array( &$result ) ) ; + } + + return $result ; + } + + function finalise( $name, &$result ) { + $callback = array( $this, "{$name}__finalise" ) ; + if ( is_callable( $callback ) ) { + call_user_func_array( $callback, array( &$result ) ) ; + } + + return $result ; + } + + function store ( &$result, $subres, $storetag = NULL ) { + $result['text'] .= $subres['text'] ; + + $globalcb = array( $this, "{$result['name']}_STR" ) ; + $callback = array( $this, $storetag ? "{$result['name']}_{$storetag}" : "{$result['name']}_{$subres['name']}" ) ; + + if ( is_callable( $callback ) ) { + call_user_func_array( $callback, array( &$result, $subres ) ) ; + } + elseif ( is_callable( $globalcb ) ) { + call_user_func_array( $globalcb, array( &$result, $subres ) ) ; + } + elseif ( $storetag ) { + if ( !isset( $result[$storetag] ) ) $result[$storetag] = $subres ; + else { + if ( isset( $result[$storetag]['text'] ) ) $result[$storetag] = array( $result[$storetag] ) ; + $result[$storetag][] = $subres ; + } + } + } +} + +/** + * By inheriting from Packrat instead of Parser, the parser will run in linear time (instead of exponential like + * Parser), but will require a lot more memory, since every match-attempt at every position is memorised. + * + * We now use a string as a byte-array to store position information rather than a straight array for memory reasons. This + * means there is a (roughly) 8MB limit on the size of the string we can parse + * + * @author Hamish Friedlander + */ +class Packrat extends Parser { + function __construct( $string ) { + parent::__construct( $string ) ; + + $max = unpack( 'N', "\x00\xFD\xFF\xFF" ) ; + if ( strlen( $string ) > $max[1] ) user_error( 'Attempting to parse string longer than Packrat Parser can handle', E_USER_ERROR ) ; + + $this->packstatebase = str_repeat( "\xFF", strlen( $string )*3 ) ; + $this->packstate = array() ; + $this->packres = array() ; + } + + function packhas( $key, $pos ) { + $pos *= 3 ; + return isset( $this->packstate[$key] ) && $this->packstate[$key][$pos] != "\xFF" ; + } + + function packread( $key, $pos ) { + $pos *= 3 ; + if ( $this->packstate[$key][$pos] == "\xFE" ) return FALSE ; + + $this->pos = ord($this->packstate[$key][$pos]) << 16 | ord($this->packstate[$key][$pos+1]) << 8 | ord($this->packstate[$key][$pos+2]) ; + return $this->packres["$key:$pos"] ; + } + + function packwrite( $key, $pos, $res ) { + if ( !isset( $this->packstate[$key] ) ) $this->packstate[$key] = $this->packstatebase ; + + $pos *= 3 ; + + if ( $res !== FALSE ) { + $i = pack( 'N', $this->pos ) ; + + $this->packstate[$key][$pos] = $i[1] ; + $this->packstate[$key][$pos+1] = $i[2] ; + $this->packstate[$key][$pos+2] = $i[3] ; + + $this->packres["$key:$pos"] = $res ; + } + else { + $this->packstate[$key][$pos] = "\xFE" ; + } + + return $res ; + } +} + +/** + * FalseOnlyPackrat only remembers which results where false. Experimental. + * + * @author Hamish Friedlander + */ +class FalseOnlyPackrat extends Parser { + function __construct( $string ) { + parent::__construct( $string ) ; + + $this->packstatebase = str_repeat( '.', strlen( $string ) ) ; + $this->packstate = array() ; + } + + function packhas( $key, $pos ) { + return isset( $this->packstate[$key] ) && $this->packstate[$key][$pos] == 'F' ; + } + + function packread( $key, $pos ) { + return FALSE ; + } + + function packwrite( $key, $pos, $res ) { + if ( !isset( $this->packstate[$key] ) ) $this->packstate[$key] = $this->packstatebase ; + + if ( $res === FALSE ) { + $this->packstate[$key][$pos] = 'F' ; + } + + return $res ; + } +} + +/** + * Conservative Packrat will only memo-ize a result on the second hit, making it more memory-lean than Packrat, + * but less likely to go exponential that Parser. Because the store logic is much more complicated this is a net + * loss over Parser for many simple grammars. + * + * @author Hamish Friedlander + */ +class ConservativePackrat extends Parser { + function packhas( $key ) { + return isset( $this->packres[$key] ) && $this->packres[$key] !== NULL ; + } + + function packread( $key ) { + $this->pos = $this->packpos[$key]; + return $this->packres[$key] ; + } + + function packwrite( $key, $res ) { + if ( isset( $this->packres[$key] ) ) { + $this->packres[$key] = $res ; + $this->packpos[$key] = $this->pos ; + } + else { + $this->packres[$key] = NULL ; + } + return $res ; + } +} + diff --git a/thirdparty/php-peg/README.md b/thirdparty/php-peg/README.md new file mode 100644 index 000000000..d327dc2f2 --- /dev/null +++ b/thirdparty/php-peg/README.md @@ -0,0 +1,230 @@ +# PHP PEG - A PEG compiler for parsing text in PHP + +This is a Paring Expression Grammar compiler for PHP. PEG parsers are an alternative to other CFG grammars that includes both tokenization +and lexing in a single top down grammar. For a basic overview of the subject, see http://en.wikipedia.org/wiki/Parsing_expression_grammar + +## Quick start + +- Write a parser. A parser is a PHP class with a grammar contained within it in a special syntax. The filetype is .peg.inc. See the examples directory. +- Compile the parser. php ./cli.php ExampleParser.peg.inc > ExampleParser.php +- Use the parser (you can also include code to do this in the input parser - again see the examples directory): + +

+	$x = new ExampleParser( 'string to parse' ) ;
+	$res = $x->match_Expr() ;
+
+ +### Parser Format + +Parsers are contained within a PHP file, in one or more special comment blocks that start with `/*!* [name | !pragma]` (like a docblock, but with an +exclamation mark in the middle of the stars) + +Lexically, these blocks are a set of rules, each consisting of a name token, a matching rule and a set of attached functions. +The name token must contain no whitespace and end with a `:` character. The matching rule and functions are on the same line or on the indented lines below. + +You can have multiple comment blocks, all of which are treated as contiguous for the purpose of compiling. During compilation these blocks will be replaced +with a set of "matching" functions (functions which match a string against their rules) for each rule in the block. + +The optional name marks the start of a new set of parser rules. This is currently unused, but might be used in future for opimization & debugging purposes. +If unspecified, it defaults to the same name as the previous parser comment block, or 'Anonymous Parser' if no name has ever been set. + +If the name starts with an '!' symbol, that comment block is a pragma, and is treated not as some part of the parser, but as a special block of meta-data + +##### Tricks and traps + +We allow indenting a parser block, but only in a consistant manner - whatever the indent of the /*** marker becomes the "base" indent, and needs to be used +for all lines. You can mix tabs and spaces, but the indent must always be an exact match - if the "base" indent is a tab then two spaces, every line within the +block also needs indenting with a tab then two spaces, not two tabs (even if in your editor, that gives the same indent). + +Any line with more than the "base" indent is considered a continuation of the previous rule + +Any line with less than the "base" indent is an error + +This might get looser if I get around to re-writing the internal "parser parser" in php-peg, bootstrapping the whole thing + +### Rules + +PEG matching rules try to follow standard PEG format, summarised thusly: + +
+	token* - Token is optionally repeated
+	token+ - Token is repeated at least one
+	token? - Token is optionally present
+
+	tokena tokenb - Token tokenb follows tokena, both of which are present
+	tokena | tokenb - One of tokena or tokenb are present, prefering tokena
+
+	&token - Token is present next (but not consumed by parse)
+	!token - Token is not present next (but not consumed by parse)
+
+ 	( expression ) - Grouping for priority
+
+ +But with these extensions: + +
+	< or > - Optionally match whitespace
+	[ or ] - Require some whitespace
+
+ +### Tokens + +Tokens may be + + - bare-words, which are recursive matchers - references to token rules defined elsewhere in the grammar, + - literals, surrounded by `"` or `'` quote pairs. No escaping support is provided in literals. + - regexs, surrounded by `/` pairs. + - expressions - single words (match \w+) starting with `$` or more complex surrounded by `${ }` which call a user defined function to perform the match + +##### Regular expression tokens + +Automatically anchored to the current string start - do not include a string start anchor (`^`) anywhere. Always acts as when the 'x' flag is enabled in PHP - +whitespace is ignored unless escaped, and '#' stats a comment. + +Be careful when ending a regular expression token - the '*/' pattern (as in /foo\s*/) will end a PHP comment. Since the 'x' flag is always active, +just split with a space (as in / foo \s* /) + +### Expressions + +Expressions allow run-time calculated matching. You can embed an expression within a literal or regex token to +match against a calculated value, or simply specify the expression as a token to (optionally) internally handle matching +and generate a result. + +Expressions will try a variety of scopes to find a value. It will look for variables already set in the current result, +rule-attached functions and a variety of other functions and constants. + +Tried in this order + +- against current result +- against containing expression stack in order (for sub-expressions only) + - against parser instance as variable + - against parser instance as rule-attached method INCLUDING `$` ( i.e. `function $foo()` ) + - against parser instance as method INCLUDING `$` + - as global method +- as constant + +##### Tricks and traps + +Be careful against matching against results + +

+	quoted_good: q:/['"]/ string "$q"
+	quoted_bad:  q:/['"]/ string $q
+
+ +`"$q"` matches against the value of q again. `$q` simply returns the value of q, without doing any matching + +### Named matching rules + +Tokens and groups can be given names by prepending name and `:`, e.g., + +

+	rulea: "'" name:( tokena tokenb )* "'"
+
+ +There must be no space betweeen the name and the `:` + +

+	badrule: "'" name : ( tokena tokenb )* "'"
+
+ +Recursive matchers can be given a name the same as their rule name by prepending with just a `:`. These next two rules are equivilent + +

+	rulea: tokena tokenb:tokenb
+	rulea: tokena :tokenb
+
+ +### Rule-attached functions + +Each rule can have a set of functions attached to it. These functions can be defined + +- in-grammar by indenting the function body after the rule +- in-class after close of grammar comment by defining a regular method who's name is `{$rulename}_{$functionname}`, or `{$rulename}{$functionname}` if function name starts with `_` +- in a sub class + +All functions that are not in-grammar must have PHP compatible names (see PHP name mapping). In-grammar functions will have their names converted if needed. + +All these definitions define the same rule-attached function + +

+	class A extends Parser {
+	/**Parser
+	foo: bar baz
+	  function bar() {}
+	* /
+
+	  function foo_bar() {}
+	}
+
+	class B extends A {
+	  function foo_bar() {}
+	}
+
+ +### PHP name mapping + +Rules in the grammar map to php functions named `match_{$rulename}`. However rule names can contain characters that php functions can't. +These characters are remapped: + +

+	'-' => '_'
+	'$' => 'DLR'
+	'*' => 'STR'
+
+ +Other dis-allowed characters are removed. + +## Results + +Results are a tree of nested arrays. + +Without any specific control, each rules result will just be the text it matched against in a `['text']` member. This member must always exist. + +Marking a subexpression, literal, regex or recursive match with a name (see Named matching rules) will insert a member into the +result array named that name. If there is only one match it will be a single result array. If there is more than one match it will be an array of arrays. + +You can override result storing by specifying a rule-attached function with the given name. It will be called with a reference to the current result array +and the sub-match - in this case the default storage action will not occur. + +If you specify a rule-attached function for a recursive match, you do not need to name that token at all - it will be call automatically. E.g. + +

+	rulea: tokena tokenb
+	  function tokenb ( &$res, $sub ) { print 'Will be called, even though tokenb is not named or marked with a :' ; }
+
+ +You can also specify a rule-attached function called `*`, which will be called with every recursive match made + +

+	rulea: tokena tokenb
+	  function * ( &$res, $sub ) { print 'Will be called for both tokena and tokenb' ; }
+
+ +### Silent matches + +By default all matches are added to the 'text' property of a result. By prepending a member with `.` that match will not be added to the ['text'] member. This +doesn't affect the other result properties that named rules' add. + +### Pragmas + +When opening a parser comment block, if instead of a name (or no name) you put a word starting with '!', that comment block is treated as a pragma - not +part of the parser language itself, but some other instruction to the compiler. These pragmas are currently understood: + + !silent + + This is a comment that should only appear in the source code. Don't output it in the generated code + + !insert_autogen_warning + + Insert a warning comment into the generated code at this point, warning that the file is autogenerated and not to edit it + +## TODO + +- Allow configuration of whitespace - specify what matches, and wether it should be injected into results as-is, collapsed, or not at all +- Allow inline-ing of rules into other rules for speed +- More optimisation +- Make Parser-parser be self-generated, instead of a bad hand rolled parser like it is now. +- Slighly more powerfull expressions: `${parent.q}`, `${foo()->bar}`, etc. +- Need to properly escape all literals. Expressions currently need to be in '', not "" +- PHP token parser, and other token streams, instead of strings only like now diff --git a/thirdparty/php-peg/cli.php b/thirdparty/php-peg/cli.php new file mode 100644 index 000000000..ab979615d --- /dev/null +++ b/thirdparty/php-peg/cli.php @@ -0,0 +1,5 @@ + '}', '[' => ']', '(' => ')', '<' => '>' ) ; + return $a[$res['q']] ; + } + +freequote-unmatched: "qq" q:/./ string '$q' + +quoted-string: freequote-matched | freequote-unmatched | simplequote + +*/ + +} diff --git a/thirdparty/php-peg/examples/Calculator.peg.inc b/thirdparty/php-peg/examples/Calculator.peg.inc new file mode 100644 index 000000000..f15d00c4c --- /dev/null +++ b/thirdparty/php-peg/examples/Calculator.peg.inc @@ -0,0 +1,63 @@ + | '(' > Expr > ')' > + function Number( &$result, $sub ) { + $result['val'] = $sub['text'] ; + } + function Expr( &$result, $sub ) { + $result['val'] = $sub['val'] ; + } + +Times: '*' > operand:Value > +Div: '/' > operand:Value > +Product: Value > ( Times | Div ) * + function Value( &$result, $sub ) { + $result['val'] = $sub['val'] ; + } + function Times( &$result, $sub ) { + $result['val'] *= $sub['operand']['val'] ; + } + function Div( &$result, $sub ) { + $result['val'] /= $sub['operand']['val'] ; + } + +Plus: '+' > operand:Product > +Minus: '-' > operand:Product > +Sum: Product > ( Plus | Minus ) * + function Product( &$result, $sub ) { + $result['val'] = $sub['val'] ; + } + function Plus( &$result, $sub ) { + $result['val'] += $sub['operand']['val'] ; + } + function Minus( &$result, $sub ) { + $result['val'] -= $sub['operand']['val'] ; + } + +Expr: Sum + function Sum( &$result, $sub ) { + $result['val'] = $sub['val'] ; + } + +*/ + +} + +$x = new Calculator( '(2 + 4) * 3 - 10' ) ; +$res = $x->match_Expr() ; +if ( $res === FALSE ) { + print "No Match\n" ; +} +else { + print_r( $res ) ; +} + + + diff --git a/thirdparty/php-peg/examples/EqualRepeat.peg.inc b/thirdparty/php-peg/examples/EqualRepeat.peg.inc new file mode 100644 index 000000000..ad7ec74f9 --- /dev/null +++ b/thirdparty/php-peg/examples/EqualRepeat.peg.inc @@ -0,0 +1,36 @@ +match_X() ; + print "$str\n" ; + print $r ? print_r( $r, true ) : 'No Match' ; + print "\n\n" ; +} + +match( 'aabbcc' ) ; // Should match +match( 'aaabbbccc' ) ; // Should match + +match( 'aabbbccc' ) ; // Should not match +match( 'aaabbccc' ) ; // Should not match +match( 'aaabbbcc' ) ; // Should not match + +match( 'aaabbbcccc' ) ; // Should not match diff --git a/thirdparty/php-peg/examples/Rfc822.peg.inc b/thirdparty/php-peg/examples/Rfc822.peg.inc new file mode 100644 index 000000000..839491d05 --- /dev/null +++ b/thirdparty/php-peg/examples/Rfc822.peg.inc @@ -0,0 +1,88 @@ +@,;:\\".\[\]\x80-\xFF]+/ + +qtext-chars: /[^"\\\x0D]+/ + +qtext: linear-white-space | qtext-chars + +quoted-pair: /\\[\x00-\x7F]/ + +quoted-string: .'"' ( quoted-pair | qtext )* .'"' + +word: atom | quoted-string + +phrase: (word >)+ + +dtext-chars: /[^\[\]\\\r]+/ + +dtext: linear-white-space | dtext-chars + +domain-literal: "[" ( dtext | quoted-pair )* "]" + +domain-ref: atom + +sub-domain: domain-ref | domain-literal + +domain: sub-domain ("." sub-domain)* + +route: "@" domain ("," "@" domain)* ":" + +route-addr: "<" route? addr-spec ">" + function addr_spec ( &$self, $sub ) { + $self['addr_spec'] = $sub['text'] ; + } + +local-part: word ("." word)* + +addr-spec: local-part "@" domain + +mailbox: ( addr-spec | phrase route-addr ) > + function __construct( &$self ) { + $self['phrase'] = NULL ; + $self['address'] = NULL ; + } + function phrase ( &$self, $sub ) { + $self['phrase'] = $sub['text'] ; + } + function addr_spec ( &$self, $sub ) { + $self['address'] = $sub['text'] ; + } + function route_addr ( &$self, $sub ) { + $self['address'] = $sub['addr_spec'] ; + } + +group: phrase ":" ( mailbox ("," mailbox)* )? ";" + +address: :mailbox | group + +address-header: address (<","> address)* + function __construct( &$self ) { + $self['addresses'] = array() ; + } + function address( &$self, $sub ) { + $self['addresses'][] = $sub['mailbox'] ; + } + +*/ + +} + +$p = new Rfc822( 'John Byorgson , "Akira \"Bad Boy\" Kenada" ' ) ; +print_r( $p->match_address_header() ) ; diff --git a/thirdparty/php-peg/examples/Rfc822UTF8.peg.inc b/thirdparty/php-peg/examples/Rfc822UTF8.peg.inc new file mode 100644 index 000000000..b2605a6d4 --- /dev/null +++ b/thirdparty/php-peg/examples/Rfc822UTF8.peg.inc @@ -0,0 +1,30 @@ +@,;:\\".\[\]]))+/u + +qtext-chars: /[^"\\\x0D]+/u + +quoted-pair: /\\./u + +*/ + +} + +/** + * Some trial code. Remove soon + */ +$p = new Rfc822UTF8( 'JØhn ByØrgsØn , "アキラ" ' ) ; +print_r( $p->match_address_header() ) ; + /* */ From f3c671988f878f99c8bc2d510dc50f513381d9bd Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Wed, 9 Feb 2011 17:31:16 +1300 Subject: [PATCH 02/15] ENHANCEMENT: Add first version of SSTemplateParser, the new php-peg based template compiler --- core/SSTemplateParser.php | 2373 +++++++++++++++++++++++++++++++++ core/SSTemplateParser.php.inc | 503 +++++++ 2 files changed, 2876 insertions(+) create mode 100644 core/SSTemplateParser.php create mode 100644 core/SSTemplateParser.php.inc diff --git a/core/SSTemplateParser.php b/core/SSTemplateParser.php new file mode 100644 index 000000000..7d46acbb5 --- /dev/null +++ b/core/SSTemplateParser.php @@ -0,0 +1,2373 @@ +string, 0, $parser->pos); + + preg_match_all('/\r\n|\r|\n/', $prior, $matches); + $line = count($matches[0])+1; + + parent::__construct("Parse error in template on line $line. Error was: $message"); + } + +} + +/** +This is the parser for the SilverStripe template language. It gets called on a string and uses a php-peg parser to match +that string against the language structure, building up the PHP code to execute that structure as it parses +*/ +class SSTemplateParser extends Parser { + + protected $includeDebuggingComments = false; + + function construct($name) { + $result = parent::construct($name); + $result['tags'] = array(); + return $result; + } + + function DLRBlockName() { + return '-none-'; + } + + /* Word: / [A-Za-z_] [A-Za-z0-9_]* / */ + function match_Word ($substack = array()) { + $result = array("name"=>"Word", "text"=>""); + $_0 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_0->expand('/ [A-Za-z_] [A-Za-z0-9_]* /') ) ) !== FALSE) { + $result["text"] .= $subres; + return $result; + } + else { return FALSE; } + } + + + /* Number: / [0-9]+ / */ + function match_Number ($substack = array()) { + $result = array("name"=>"Number", "text"=>""); + $_2 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_2->expand('/ [0-9]+ /') ) ) !== FALSE) { + $result["text"] .= $subres; + return $result; + } + else { return FALSE; } + } + + + /* Value: / [A-Za-z0-9_]+ / */ + function match_Value ($substack = array()) { + $result = array("name"=>"Value", "text"=>""); + $_4 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_4->expand('/ [A-Za-z0-9_]+ /') ) ) !== FALSE) { + $result["text"] .= $subres; + return $result; + } + else { return FALSE; } + } + + + /* Arguments: :Argument ( < "," < :Argument )* */ + function match_Arguments ($substack = array()) { + $result = $this->construct( "Arguments" ); + $_13 = NULL; + do { + $key = "Argument"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Argument" ); + } + else { $_13 = FALSE; break; } + while (true) { + $res_12 = $result; + $pos_12 = $this->pos; + $_11 = NULL; + do { + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == ",") { + $this->pos += 1; + $result["text"] .= ","; + } + else { $_11 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "Argument"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Argument" ); + } + else { $_11 = FALSE; break; } + $_11 = TRUE; break; + } + while(0); + if( $_11 === FALSE) { + $result = $res_12; + $this->pos = $pos_12; + unset( $res_12 ); + unset( $pos_12 ); + break; + } + } + $_13 = TRUE; break; + } + while(0); + if( $_13 === TRUE ) { + return $this->finalise( "Arguments", $result ); + } + if( $_13 === FALSE) { return FALSE; } + } + + + + + /** Values are bare words in templates, but strings in PHP. We rely on PHP's type conversion to back-convert strings to numbers when needed */ + function Arguments_Argument(&$res, $sub) { + if (isset($res['php'])) $res['php'] .= ', '; + else $res['php'] = ''; + + $res['php'] .= ($sub['ArgumentMode'] == 'default') ? $sub['string_php'] : $sub['php']; + } + + /* Call: Method:Word ( "(" < :Arguments? > ")" )? */ + function match_Call ($substack = array()) { + $result = $this->construct( "Call" ); + $_23 = NULL; + do { + $key = "Word"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Method" ); + } + else { $_23 = FALSE; break; } + $res_22 = $result; + $pos_22 = $this->pos; + $_21 = NULL; + do { + if (substr($this->string,$this->pos,1) == "(") { + $this->pos += 1; + $result["text"] .= "("; + } + else { $_21 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $res_18 = $result; + $pos_18 = $this->pos; + $key = "Arguments"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Arguments(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Arguments" ); + } + else { + $result = $res_18; + $this->pos = $pos_18; + unset( $res_18 ); + unset( $pos_18 ); + } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == ")") { + $this->pos += 1; + $result["text"] .= ")"; + } + else { $_21 = FALSE; break; } + $_21 = TRUE; break; + } + while(0); + if( $_21 === FALSE) { + $result = $res_22; + $this->pos = $pos_22; + unset( $res_22 ); + unset( $pos_22 ); + } + $_23 = TRUE; break; + } + while(0); + if( $_23 === TRUE ) { + return $this->finalise( "Call", $result ); + } + if( $_23 === FALSE) { return FALSE; } + } + + + /* LookupStep: :Call &"." */ + function match_LookupStep ($substack = array()) { + $result = $this->construct( "LookupStep" ); + $_27 = NULL; + do { + $key = "Call"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Call(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Call" ); + } + else { $_27 = FALSE; break; } + $res_26 = $result; + $pos_26 = $this->pos; + if (substr($this->string,$this->pos,1) == ".") { + $this->pos += 1; + $result["text"] .= "."; + $result = $res_26; + $this->pos = $pos_26; + } + else { + $result = $res_26; + $this->pos = $pos_26; + $_27 = FALSE; break; + } + $_27 = TRUE; break; + } + while(0); + if( $_27 === TRUE ) { + return $this->finalise( "LookupStep", $result ); + } + if( $_27 === FALSE) { return FALSE; } + } + + + /* LastLookupStep: :Call */ + function match_LastLookupStep ($substack = array()) { + $result = $this->construct( "LastLookupStep" ); + $key = "Call"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Call(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Call" ); + return $this->finalise( "LastLookupStep", $result ); + } + else { return FALSE; } + } + + + /* Lookup: LookupStep ("." LookupStep)* "." LastLookupStep | LastLookupStep */ + function match_Lookup ($substack = array()) { + $result = $this->construct( "Lookup" ); + $_41 = NULL; + do { + $res_30 = $result; + $pos_30 = $this->pos; + $_38 = NULL; + do { + $key = "LookupStep"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_LookupStep(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_38 = FALSE; break; } + while (true) { + $res_35 = $result; + $pos_35 = $this->pos; + $_34 = NULL; + do { + if (substr($this->string,$this->pos,1) == ".") { + $this->pos += 1; + $result["text"] .= "."; + } + else { $_34 = FALSE; break; } + $key = "LookupStep"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_LookupStep(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + } + else { $_34 = FALSE; break; } + $_34 = TRUE; break; + } + while(0); + if( $_34 === FALSE) { + $result = $res_35; + $this->pos = $pos_35; + unset( $res_35 ); + unset( $pos_35 ); + break; + } + } + if (substr($this->string,$this->pos,1) == ".") { + $this->pos += 1; + $result["text"] .= "."; + } + else { $_38 = FALSE; break; } + $key = "LastLookupStep"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_LastLookupStep(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_38 = FALSE; break; } + $_38 = TRUE; break; + } + while(0); + if( $_38 === TRUE ) { $_41 = TRUE; break; } + $result = $res_30; + $this->pos = $pos_30; + $key = "LastLookupStep"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_LastLookupStep(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_41 = TRUE; break; + } + $result = $res_30; + $this->pos = $pos_30; + $_41 = FALSE; break; + } + while(0); + if( $_41 === TRUE ) { + return $this->finalise( "Lookup", $result ); + } + if( $_41 === FALSE) { return FALSE; } + } + + + + + function Lookup__construct(&$res) { + $res['php'] = '$item'; + $res['LookupSteps'] = array(); + } + + function Lookup_AddLookupStep(&$res, $sub, $method) { + $res['LookupSteps'][] = $sub; + + $property = $sub['Call']['Method']['text']; + + if (isset($sub['Call']['Arguments']) && $arguments = $sub['Call']['Arguments']['php']) { + $res['php'] .= "->$method('$property', array($arguments), true)"; + } + else { + $res['php'] .= "->$method('$property', null, true)"; + } + } + + function Lookup_LookupStep(&$res, $sub) { + $this->Lookup_AddLookupStep($res, $sub, 'obj'); + } + + function Lookup_LastLookupStep(&$res, $sub) { + $this->Lookup_AddLookupStep($res, $sub, 'XML_val'); + } + + /* SimpleInjection: '$' :Lookup */ + function match_SimpleInjection ($substack = array()) { + $result = $this->construct( "SimpleInjection" ); + $_45 = NULL; + do { + if (substr($this->string,$this->pos,1) == '$') { + $this->pos += 1; + $result["text"] .= '$'; + } + else { $_45 = FALSE; break; } + $key = "Lookup"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Lookup(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Lookup" ); + } + else { $_45 = FALSE; break; } + $_45 = TRUE; break; + } + while(0); + if( $_45 === TRUE ) { + return $this->finalise( "SimpleInjection", $result ); + } + if( $_45 === FALSE) { return FALSE; } + } + + + /* BracketInjection: '{$' :Lookup "}" */ + function match_BracketInjection ($substack = array()) { + $result = $this->construct( "BracketInjection" ); + $_51 = NULL; + do { + $_47 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_47->expand('{$') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_51 = FALSE; break; } + $key = "Lookup"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Lookup(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Lookup" ); + } + else { $_51 = FALSE; break; } + if (substr($this->string,$this->pos,1) == "}") { + $this->pos += 1; + $result["text"] .= "}"; + } + else { $_51 = FALSE; break; } + $_51 = TRUE; break; + } + while(0); + if( $_51 === TRUE ) { + return $this->finalise( "BracketInjection", $result ); + } + if( $_51 === FALSE) { return FALSE; } + } + + + /* Injection: BracketInjection | SimpleInjection */ + function match_Injection ($substack = array()) { + $result = $this->construct( "Injection" ); + $_56 = NULL; + do { + $res_53 = $result; + $pos_53 = $this->pos; + $key = "BracketInjection"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BracketInjection(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_56 = TRUE; break; + } + $result = $res_53; + $this->pos = $pos_53; + $key = "SimpleInjection"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_SimpleInjection(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_56 = TRUE; break; + } + $result = $res_53; + $this->pos = $pos_53; + $_56 = FALSE; break; + } + while(0); + if( $_56 === TRUE ) { + return $this->finalise( "Injection", $result ); + } + if( $_56 === FALSE) { return FALSE; } + } + + + + function Injection_STR(&$res, $sub) { + $res['php'] = '$val .= '. $sub['Lookup']['php'] . ';'; + } + + /* DollarMarkedLookup: BracketInjection | SimpleInjection */ + function match_DollarMarkedLookup ($substack = array()) { + $result = $this->construct( "DollarMarkedLookup" ); + $_61 = NULL; + do { + $res_58 = $result; + $pos_58 = $this->pos; + $key = "BracketInjection"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BracketInjection(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_61 = TRUE; break; + } + $result = $res_58; + $this->pos = $pos_58; + $key = "SimpleInjection"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_SimpleInjection(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_61 = TRUE; break; + } + $result = $res_58; + $this->pos = $pos_58; + $_61 = FALSE; break; + } + while(0); + if( $_61 === TRUE ) { + return $this->finalise( "DollarMarkedLookup", $result ); + } + if( $_61 === FALSE) { return FALSE; } + } + + + + function DollarMarkedLookup_STR(&$res, $sub) { + $res['Lookup'] = $sub['Lookup']; + } + + /* QuotedString: q:/['"]/ String:/ (\\\\ | \\. | [^$q\\])* / '$q' */ + function match_QuotedString ($substack = array()) { + $result = $this->construct( "QuotedString" ); + $_71 = NULL; + do { + $substack[] = $result; + $result = $this->construct( "q" ); + $_63 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_63->expand('/[\'"]/') ) ) !== FALSE) { + $result["text"] .= $subres; + $subres = $result ; + $result = array_pop( $substack ) ; + $this->store( $result, $subres, 'q' ); + } + else { + $result = array_pop( $substack ) ; + $_71 = FALSE; break; + } + $substack[] = $result; + $result = $this->construct( "String" ); + $_66 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_66->expand('/ (\\\\\\\\ | \\\\. | [^$q\\\\])* /') ) ) !== FALSE) { + $result["text"] .= $subres; + $subres = $result ; + $result = array_pop( $substack ) ; + $this->store( $result, $subres, 'String' ); + } + else { + $result = array_pop( $substack ) ; + $_71 = FALSE; break; + } + $_69 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_69->expand('$q') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_71 = FALSE; break; } + $_71 = TRUE; break; + } + while(0); + if( $_71 === TRUE ) { + return $this->finalise( "QuotedString", $result ); + } + if( $_71 === FALSE) { return FALSE; } + } + + + /* FreeString: /[^,)%!=|&]+/ */ + function match_FreeString ($substack = array()) { + $result = array("name"=>"FreeString", "text"=>""); + $_73 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_73->expand('/[^,)%!=|&]+/') ) ) !== FALSE) { + $result["text"] .= $subres; + return $result; + } + else { return FALSE; } + } + + + /* Argument: +:DollarMarkedLookup | +:QuotedString | +:Lookup !(< FreeString)| +:FreeString */ + function match_Argument ($substack = array()) { + $result = $this->construct( "Argument" ); + $_92 = NULL; + do { + $res_75 = $result; + $pos_75 = $this->pos; + $key = "DollarMarkedLookup"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_DollarMarkedLookup(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "DollarMarkedLookup" ); + $_92 = TRUE; break; + } + $result = $res_75; + $this->pos = $pos_75; + $_90 = NULL; + do { + $res_77 = $result; + $pos_77 = $this->pos; + $key = "QuotedString"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_QuotedString(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "QuotedString" ); + $_90 = TRUE; break; + } + $result = $res_77; + $this->pos = $pos_77; + $_88 = NULL; + do { + $res_79 = $result; + $pos_79 = $this->pos; + $_85 = NULL; + do { + $key = "Lookup"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Lookup(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Lookup" ); + } + else { $_85 = FALSE; break; } + $res_84 = $result; + $pos_84 = $this->pos; + $_83 = NULL; + do { + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "FreeString"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_FreeString(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + } + else { $_83 = FALSE; break; } + $_83 = TRUE; break; + } + while(0); + if( $_83 === TRUE ) { + $result = $res_84; + $this->pos = $pos_84; + $_85 = FALSE; break; + } + if( $_83 === FALSE) { + $result = $res_84; + $this->pos = $pos_84; + } + $_85 = TRUE; break; + } + while(0); + if( $_85 === TRUE ) { $_88 = TRUE; break; } + $result = $res_79; + $this->pos = $pos_79; + $key = "FreeString"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_FreeString(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "FreeString" ); + $_88 = TRUE; break; + } + $result = $res_79; + $this->pos = $pos_79; + $_88 = FALSE; break; + } + while(0); + if( $_88 === TRUE ) { $_90 = TRUE; break; } + $result = $res_77; + $this->pos = $pos_77; + $_90 = FALSE; break; + } + while(0); + if( $_90 === TRUE ) { $_92 = TRUE; break; } + $result = $res_75; + $this->pos = $pos_75; + $_92 = FALSE; break; + } + while(0); + if( $_92 === TRUE ) { + return $this->finalise( "Argument", $result ); + } + if( $_92 === FALSE) { return FALSE; } + } + + + + function Argument_DollarMarkedLookup(&$res, $sub) { + $res['ArgumentMode'] = 'lookup'; + $res['php'] = $sub['Lookup']['php']; + } + + function Argument_QuotedString(&$res, $sub) { + $res['ArgumentMode'] = 'string'; + $res['php'] = "'" . $sub['String']['text'] . "'"; + } + + function Argument_Lookup(&$res, $sub) { + if (count($sub['LookupSteps']) == 1 && !isset($sub['LookupSteps'][0]['Call']['Arguments'])) { + $res['ArgumentMode'] = 'default'; + $res['lookup_php'] = $sub['php']; + $res['string_php'] = "'".$sub['LookupSteps'][0]['Call']['Method']['text']."'"; + } + else { + $res['ArgumentMode'] = 'lookup'; + $res['php'] = $sub['php']; + } + } + + function Argument_FreeString(&$res, $sub) { + $res['ArgumentMode'] = 'string'; + $res['php'] = "'" . $sub['text'] . "'"; + } + + /* ComparisonOperator: "==" | "!=" | "=" */ + function match_ComparisonOperator ($substack = array()) { + $result = $this->construct( "ComparisonOperator" ); + $_103 = NULL; + do { + $res_94 = $result; + $pos_94 = $this->pos; + $_95 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_95->expand("==") ) ) !== FALSE) { + $result["text"] .= $subres; + $_103 = TRUE; break; + } + $result = $res_94; + $this->pos = $pos_94; + $_101 = NULL; + do { + $res_97 = $result; + $pos_97 = $this->pos; + $_98 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_98->expand("!=") ) ) !== FALSE) { + $result["text"] .= $subres; + $_101 = TRUE; break; + } + $result = $res_97; + $this->pos = $pos_97; + if (substr($this->string,$this->pos,1) == "=") { + $this->pos += 1; + $result["text"] .= "="; + $_101 = TRUE; break; + } + $result = $res_97; + $this->pos = $pos_97; + $_101 = FALSE; break; + } + while(0); + if( $_101 === TRUE ) { $_103 = TRUE; break; } + $result = $res_94; + $this->pos = $pos_94; + $_103 = FALSE; break; + } + while(0); + if( $_103 === TRUE ) { + return $this->finalise( "ComparisonOperator", $result ); + } + if( $_103 === FALSE) { return FALSE; } + } + + + /* Comparison: Argument < ComparisonOperator > Argument */ + function match_Comparison ($substack = array()) { + $result = $this->construct( "Comparison" ); + $_110 = NULL; + do { + $key = "Argument"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_110 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "ComparisonOperator"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ComparisonOperator(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_110 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "Argument"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_110 = FALSE; break; } + $_110 = TRUE; break; + } + while(0); + if( $_110 === TRUE ) { + return $this->finalise( "Comparison", $result ); + } + if( $_110 === FALSE) { return FALSE; } + } + + + + function Comparison_Argument(&$res, $sub) { + if ($sub['ArgumentMode'] == 'default') { + if (isset($res['php'])) $res['php'] .= $sub['string_php']; + else $res['php'] = $sub['lookup_php']; + } + else { + if (!isset($res['php'])) $res['php'] = ''; + $res['php'] .= $sub['php']; + } + } + + function Comparison_ComparisonOperator(&$res, $sub) { + $res['php'] .= ($sub['text'] == '=' ? '==' : $sub['text']); + } + + /* PresenceCheck: Argument */ + function match_PresenceCheck ($substack = array()) { + $result = $this->construct( "PresenceCheck" ); + $key = "Argument"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + return $this->finalise( "PresenceCheck", $result ); + } + else { return FALSE; } + } + + + + function PresenceCheck_Argument(&$res, $sub) { + if ($sub['ArgumentMode'] == 'string') { + $res['php'] = '((bool)'.$sub['php'].')'; + } + else { + $php = ($sub['ArgumentMode'] == 'default' ? $sub['lookup_php'] : $sub['php']); + // TODO: kinda hacky - maybe we need a way to pass state down the parse chain so + // Lookup_LastLookupStep and Argument_BareWord can produce hasValue instead of XML_val + $res['php'] = str_replace('->XML_val', '->hasValue', $php); + } + } + + /* IfArgumentPortion: Comparison | PresenceCheck */ + function match_IfArgumentPortion ($substack = array()) { + $result = $this->construct( "IfArgumentPortion" ); + $_116 = NULL; + do { + $res_113 = $result; + $pos_113 = $this->pos; + $key = "Comparison"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comparison(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_116 = TRUE; break; + } + $result = $res_113; + $this->pos = $pos_113; + $key = "PresenceCheck"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_PresenceCheck(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_116 = TRUE; break; + } + $result = $res_113; + $this->pos = $pos_113; + $_116 = FALSE; break; + } + while(0); + if( $_116 === TRUE ) { + return $this->finalise( "IfArgumentPortion", $result ); + } + if( $_116 === FALSE) { return FALSE; } + } + + + + function IfArgumentPortion_STR(&$res, $sub) { + $res['php'] = $sub['php']; + } + + /* BooleanOperator: "||" | "&&" */ + function match_BooleanOperator ($substack = array()) { + $result = $this->construct( "BooleanOperator" ); + $_123 = NULL; + do { + $res_118 = $result; + $pos_118 = $this->pos; + $_119 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_119->expand("||") ) ) !== FALSE) { + $result["text"] .= $subres; + $_123 = TRUE; break; + } + $result = $res_118; + $this->pos = $pos_118; + $_121 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_121->expand("&&") ) ) !== FALSE) { + $result["text"] .= $subres; + $_123 = TRUE; break; + } + $result = $res_118; + $this->pos = $pos_118; + $_123 = FALSE; break; + } + while(0); + if( $_123 === TRUE ) { + return $this->finalise( "BooleanOperator", $result ); + } + if( $_123 === FALSE) { return FALSE; } + } + + + /* IfArgument: :IfArgumentPortion ( < :BooleanOperator < :IfArgumentPortion )* */ + function match_IfArgument ($substack = array()) { + $result = $this->construct( "IfArgument" ); + $_132 = NULL; + do { + $key = "IfArgumentPortion"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgumentPortion(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "IfArgumentPortion" ); + } + else { $_132 = FALSE; break; } + while (true) { + $res_131 = $result; + $pos_131 = $this->pos; + $_130 = NULL; + do { + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "BooleanOperator"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BooleanOperator(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "BooleanOperator" ); + } + else { $_130 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "IfArgumentPortion"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgumentPortion(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "IfArgumentPortion" ); + } + else { $_130 = FALSE; break; } + $_130 = TRUE; break; + } + while(0); + if( $_130 === FALSE) { + $result = $res_131; + $this->pos = $pos_131; + unset( $res_131 ); + unset( $pos_131 ); + break; + } + } + $_132 = TRUE; break; + } + while(0); + if( $_132 === TRUE ) { + return $this->finalise( "IfArgument", $result ); + } + if( $_132 === FALSE) { return FALSE; } + } + + + + function IfArgument__construct(&$res){ + $res['php'] = ''; + } + function IfArgument_IfArgumentPortion(&$res, $sub) { + $res['php'] .= $sub['php']; + } + + function IfArgument_BooleanOperator(&$res, $sub) { + $res['php'] .= $sub['text']; + } + + /* IfPart: '<%' < 'if' < :IfArgument > '%>' :Template? */ + function match_IfPart ($substack = array()) { + $result = $this->construct( "IfPart" ); + $_145 = NULL; + do { + $_134 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_134->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_145 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_137 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_137->expand('if') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_145 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "IfArgument"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgument(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "IfArgument" ); + } + else { $_145 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_142 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_142->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_145 = FALSE; break; } + $res_144 = $result; + $pos_144 = $this->pos; + $key = "Template"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Template" ); + } + else { + $result = $res_144; + $this->pos = $pos_144; + unset( $res_144 ); + unset( $pos_144 ); + } + $_145 = TRUE; break; + } + while(0); + if( $_145 === TRUE ) { + return $this->finalise( "IfPart", $result ); + } + if( $_145 === FALSE) { return FALSE; } + } + + + /* ElseIfPart: '<%' < 'else_if' < :IfArgument > '%>' :Template? */ + function match_ElseIfPart ($substack = array()) { + $result = $this->construct( "ElseIfPart" ); + $_158 = NULL; + do { + $_147 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_147->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_158 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_150 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_150->expand('else_if') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_158 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "IfArgument"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgument(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "IfArgument" ); + } + else { $_158 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_155 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_155->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_158 = FALSE; break; } + $res_157 = $result; + $pos_157 = $this->pos; + $key = "Template"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Template" ); + } + else { + $result = $res_157; + $this->pos = $pos_157; + unset( $res_157 ); + unset( $pos_157 ); + } + $_158 = TRUE; break; + } + while(0); + if( $_158 === TRUE ) { + return $this->finalise( "ElseIfPart", $result ); + } + if( $_158 === FALSE) { return FALSE; } + } + + + /* ElsePart: '<%' < 'else' > '%>' :Template? */ + function match_ElsePart ($substack = array()) { + $result = $this->construct( "ElsePart" ); + $_169 = NULL; + do { + $_160 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_160->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_169 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_163 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_163->expand('else') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_169 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_166 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_166->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_169 = FALSE; break; } + $res_168 = $result; + $pos_168 = $this->pos; + $key = "Template"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Template" ); + } + else { + $result = $res_168; + $this->pos = $pos_168; + unset( $res_168 ); + unset( $pos_168 ); + } + $_169 = TRUE; break; + } + while(0); + if( $_169 === TRUE ) { + return $this->finalise( "ElsePart", $result ); + } + if( $_169 === FALSE) { return FALSE; } + } + + + /* If: IfPart ElseIfPart* ElsePart? '<%' < 'end_if' > '%>' */ + function match_If ($substack = array()) { + $result = $this->construct( "If" ); + $_182 = NULL; + do { + $key = "IfPart"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfPart(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_182 = FALSE; break; } + while (true) { + $res_172 = $result; + $pos_172 = $this->pos; + $key = "ElseIfPart"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ElseIfPart(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { + $result = $res_172; + $this->pos = $pos_172; + unset( $res_172 ); + unset( $pos_172 ); + break; + } + } + $res_173 = $result; + $pos_173 = $this->pos; + $key = "ElsePart"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ElsePart(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { + $result = $res_173; + $this->pos = $pos_173; + unset( $res_173 ); + unset( $pos_173 ); + } + $_174 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_174->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_182 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_177 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_177->expand('end_if') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_182 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_180 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_180->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_182 = FALSE; break; } + $_182 = TRUE; break; + } + while(0); + if( $_182 === TRUE ) { + return $this->finalise( "If", $result ); + } + if( $_182 === FALSE) { return FALSE; } + } + + + + function If__construct(&$res) { + $res['BlockName'] = 'if'; + } + + function If_IfPart(&$res, $sub) { + $res['php'] = + 'if (' . $sub['IfArgument']['php'] . ') { ' . PHP_EOL . + $sub['Template']['php'] . PHP_EOL . + '}'; + } + + function If_ElseIfPart(&$res, $sub) { + $res['php'] .= + 'else if (' . $sub['IfArgument']['php'] . ') { ' . PHP_EOL . + $sub['Template']['php'] . PHP_EOL . + '}'; + } + + function If_ElsePart(&$res, $sub) { + $res['php'] .= + 'else { ' . PHP_EOL . + $sub['Template']['php'] . PHP_EOL . + '}'; + } + + /* Require: '<%' < 'require' [ Call:(Method:Word "(" < :Arguments > ")") > '%>' */ + function match_Require ($substack = array()) { + $result = $this->construct( "Require" ); + $_202 = NULL; + do { + $_184 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_184->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_202 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_187 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_187->expand('require') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_202 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_202 = FALSE; break; } + $substack[] = $result; + $result = $this->construct( "Call" ); + $_196 = NULL; + do { + $key = "Word"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Method" ); + } + else { $_196 = FALSE; break; } + if (substr($this->string,$this->pos,1) == "(") { + $this->pos += 1; + $result["text"] .= "("; + } + else { $_196 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "Arguments"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Arguments(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Arguments" ); + } + else { $_196 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == ")") { + $this->pos += 1; + $result["text"] .= ")"; + } + else { $_196 = FALSE; break; } + $_196 = TRUE; break; + } + while(0); + if( $_196 === TRUE ) { + $subres = $result ; + $result = array_pop( $substack ) ; + $this->store( $result, $subres, 'Call' ); + } + if( $_196 === FALSE) { + $result = array_pop( $substack ) ; + $_202 = FALSE; break; + } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_200 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_200->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_202 = FALSE; break; } + $_202 = TRUE; break; + } + while(0); + if( $_202 === TRUE ) { + return $this->finalise( "Require", $result ); + } + if( $_202 === FALSE) { return FALSE; } + } + + + + function Require_Call(&$res, $sub) { + $res['php'] = "Requirements::".$sub['Method']['text'].'('.$sub['Arguments']['php'].');'; + } + + /* BlockArguments: :Argument ( < "," < :Argument)* */ + function match_BlockArguments ($substack = array()) { + $result = $this->construct( "BlockArguments" ); + $_211 = NULL; + do { + $key = "Argument"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Argument" ); + } + else { $_211 = FALSE; break; } + while (true) { + $res_210 = $result; + $pos_210 = $this->pos; + $_209 = NULL; + do { + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == ",") { + $this->pos += 1; + $result["text"] .= ","; + } + else { $_209 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "Argument"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Argument" ); + } + else { $_209 = FALSE; break; } + $_209 = TRUE; break; + } + while(0); + if( $_209 === FALSE) { + $result = $res_210; + $this->pos = $pos_210; + unset( $res_210 ); + unset( $pos_210 ); + break; + } + } + $_211 = TRUE; break; + } + while(0); + if( $_211 === TRUE ) { + return $this->finalise( "BlockArguments", $result ); + } + if( $_211 === FALSE) { return FALSE; } + } + + + /* NotBlockTag: "end_" | (("if" | "else_if" | "else" | "require") ] ) */ + function match_NotBlockTag ($substack = array()) { + $result = $this->construct( "NotBlockTag" ); + $_238 = NULL; + do { + $res_213 = $result; + $pos_213 = $this->pos; + $_214 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_214->expand("end_") ) ) !== FALSE) { + $result["text"] .= $subres; + $_238 = TRUE; break; + } + $result = $res_213; + $this->pos = $pos_213; + $_236 = NULL; + do { + $_233 = NULL; + do { + $_231 = NULL; + do { + $res_216 = $result; + $pos_216 = $this->pos; + $_217 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_217->expand("if") ) ) !== FALSE) { + $result["text"] .= $subres; + $_231 = TRUE; break; + } + $result = $res_216; + $this->pos = $pos_216; + $_229 = NULL; + do { + $res_219 = $result; + $pos_219 = $this->pos; + $_220 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_220->expand("else_if") ) ) !== FALSE) { + $result["text"] .= $subres; + $_229 = TRUE; break; + } + $result = $res_219; + $this->pos = $pos_219; + $_227 = NULL; + do { + $res_222 = $result; + $pos_222 = $this->pos; + $_223 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_223->expand("else") ) ) !== FALSE) { + $result["text"] .= $subres; + $_227 = TRUE; break; + } + $result = $res_222; + $this->pos = $pos_222; + $_225 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_225->expand("require") ) ) !== FALSE) { + $result["text"] .= $subres; + $_227 = TRUE; break; + } + $result = $res_222; + $this->pos = $pos_222; + $_227 = FALSE; break; + } + while(0); + if( $_227 === TRUE ) { $_229 = TRUE; break; } + $result = $res_219; + $this->pos = $pos_219; + $_229 = FALSE; break; + } + while(0); + if( $_229 === TRUE ) { $_231 = TRUE; break; } + $result = $res_216; + $this->pos = $pos_216; + $_231 = FALSE; break; + } + while(0); + if( $_231 === FALSE) { $_233 = FALSE; break; } + $_233 = TRUE; break; + } + while(0); + if( $_233 === FALSE) { $_236 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_236 = FALSE; break; } + $_236 = TRUE; break; + } + while(0); + if( $_236 === TRUE ) { $_238 = TRUE; break; } + $result = $res_213; + $this->pos = $pos_213; + $_238 = FALSE; break; + } + while(0); + if( $_238 === TRUE ) { + return $this->finalise( "NotBlockTag", $result ); + } + if( $_238 === FALSE) { return FALSE; } + } + + + /* ClosedBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > Zap:'%>' :Template? '<%' < 'end_' '$BlockName' > '%>' */ + function match_ClosedBlock ($substack = array()) { + $result = $this->construct( "ClosedBlock" ); + $_265 = NULL; + do { + $_240 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_240->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_265 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $res_243 = $result; + $pos_243 = $this->pos; + $key = "NotBlockTag"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $result = $res_243; + $this->pos = $pos_243; + $_265 = FALSE; break; + } + else { + $result = $res_243; + $this->pos = $pos_243; + } + $key = "Word"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "BlockName" ); + } + else { $_265 = FALSE; break; } + $res_249 = $result; + $pos_249 = $this->pos; + $_248 = NULL; + do { + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_248 = FALSE; break; } + $key = "BlockArguments"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "BlockArguments" ); + } + else { $_248 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_248 = FALSE; break; } + $_248 = TRUE; break; + } + while(0); + if( $_248 === FALSE) { + $result = $res_249; + $this->pos = $pos_249; + unset( $res_249 ); + unset( $pos_249 ); + } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $substack[] = $result; + $result = $this->construct( "Zap" ); + $_251 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_251->expand('%>') ) ) !== FALSE) { + $result["text"] .= $subres; + $subres = $result ; + $result = array_pop( $substack ) ; + $this->store( $result, $subres, 'Zap' ); + } + else { + $result = array_pop( $substack ) ; + $_265 = FALSE; break; + } + $res_254 = $result; + $pos_254 = $this->pos; + $key = "Template"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Template" ); + } + else { + $result = $res_254; + $this->pos = $pos_254; + unset( $res_254 ); + unset( $pos_254 ); + } + $_255 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_255->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_265 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_258 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_258->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_265 = FALSE; break; } + $_260 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_260->expand('$BlockName') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_265 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_263 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_263->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_265 = FALSE; break; } + $_265 = TRUE; break; + } + while(0); + if( $_265 === TRUE ) { + return $this->finalise( "ClosedBlock", $result ); + } + if( $_265 === FALSE) { return FALSE; } + } + + + + function ClosedBlock__construct(&$res) { + $res['ArgumentCount'] = 0; + } + + function ClosedBlock_BlockArguments(&$res, $sub) { + if (isset($sub['Argument']['ArgumentMode'])) { + $res['Arguments'] = array($sub['Argument']); + $res['ArgumentCount'] = 1; + } + else { + $res['Arguments'] = $sub['Argument']; + $res['ArgumentCount'] = count($res['Arguments']); + } + } + + function ClosedBlock__finalise(&$res) { + $blockname = $res['BlockName']['text']; + + $method = 'ClosedBlock_Handle_'.ucfirst(strtolower($blockname)); + if (method_exists($this, $method)) $res['php'] = $this->$method($res); + else { + throw new SSTemplateParseException('Unknown closed block "'.$blockname.'" encountered. Perhaps you are not supposed to close this block, or have mis-spelled it?', $this); + } + } + + function ClosedBlock_Handle_Control(&$res) { + if ($res['ArgumentCount'] != 1) { + throw new SSTemplateParseException('Either no or too many arguments in control block. Must be one argument only.', $this); + } + + $arg = $res['Arguments'][0]; + if ($arg['ArgumentMode'] == 'string') { + throw new SSTemplateParseException('Control block cant take string as argument.', $this); + } + + $on = str_replace('->XML_val', '->obj', ($arg['ArgumentMode'] == 'default') ? $arg['lookup_php'] : $arg['php']); + return + 'array_push($itemStack, $item); if($loop = '.$on.') foreach($loop as $key => $item) {' . PHP_EOL . + $res['Template']['php'] . PHP_EOL . + '} $item = array_pop($itemStack); '; + } + + /* OpenBlock: '<%' < !NotBlockTag OpenBlockName:Word ( [ :BlockArguments ] )? > '%>' */ + function match_OpenBlock ($substack = array()) { + $result = $this->construct( "OpenBlock" ); + $_280 = NULL; + do { + $_267 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_267->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_280 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $res_270 = $result; + $pos_270 = $this->pos; + $key = "NotBlockTag"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $result = $res_270; + $this->pos = $pos_270; + $_280 = FALSE; break; + } + else { + $result = $res_270; + $this->pos = $pos_270; + } + $key = "Word"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "OpenBlockName" ); + } + else { $_280 = FALSE; break; } + $res_276 = $result; + $pos_276 = $this->pos; + $_275 = NULL; + do { + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_275 = FALSE; break; } + $key = "BlockArguments"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "BlockArguments" ); + } + else { $_275 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_275 = FALSE; break; } + $_275 = TRUE; break; + } + while(0); + if( $_275 === FALSE) { + $result = $res_276; + $this->pos = $pos_276; + unset( $res_276 ); + unset( $pos_276 ); + } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_278 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_278->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_280 = FALSE; break; } + $_280 = TRUE; break; + } + while(0); + if( $_280 === TRUE ) { + return $this->finalise( "OpenBlock", $result ); + } + if( $_280 === FALSE) { return FALSE; } + } + + + + function OpenBlock__construct(&$res) { + $res['ArgumentCount'] = 0; + } + + function OpenBlock_BlockArguments(&$res, $sub) { + if (isset($sub['Argument']['ArgumentMode'])) { + $res['Arguments'] = array($sub['Argument']); + $res['ArgumentCount'] = 1; + } + else { + $res['Arguments'] = $sub['Argument']; + $res['ArgumentCount'] = count($res['Arguments']); + } + } + + function OpenBlock__finalise(&$res) { + $blockname = $res['OpenBlockName']['text']; + + $method = 'OpenBlock_Handle_'.ucfirst(strtolower($blockname)); + if (method_exists($this, $method)) $res['php'] = $this->$method($res); + else { + throw new SSTemplateParseException('Unknown open block "'.$blockname.'" encountered. Perhaps you missed the closing tag or have mis-spelled it?', $this); + } + } + + function OpenBlock_Handle_Include(&$res) { + if ($res['ArgumentCount'] != 1) throw new SSTemplateParseException('Include takes exactly one argument', $this); + + $arg = $res['Arguments'][0]; + $php = ($arg['ArgumentMode'] == 'default') ? $arg['string_php'] : $arg['php']; + + if($this->includeDebuggingComments) { // Add include filename comments on dev sites + return + '$val .= \'\';'. "\n". + '$val .= SSViewer::parse_template('.$php.', $item);'. "\n". + '$val .= \'\';'. "\n"; + } + else { + return + '$val .= SSViewer::execute_template('.$php.', $item);'. "\n"; + } + } + + function OpenBlock_Handle_Debug(&$res) { + if ($res['ArgumentCount'] == 0) return 'Debug::show($item);'; + else if ($res['ArgumentCount'] == 1) { + $arg = $res['Arguments'][0]; + + if ($arg['ArgumentMode'] == 'string') return 'Debug::show('.$arg['php'].');'; + + $php = ($arg['ArgumentMode'] == 'default') ? $arg['lookup_php'] : $arg['php']; + return '$val .= Debug::show('.str_replace('FINALGET!', 'cachedCall', $php).');'; + } + else { + throw new SSTemplateParseException('Debug takes 0 or 1 argument only.', $this); + } + } + + function OpenBlock_Handle_Base_tag(&$res) { + if ($res['ArgumentCount'] != 0) throw new SSTemplateParseException('Base_tag takes no arguments', $this); + return '$val .= SSViewer::get_base_tag($val);'; + } + + function OpenBlock_Handle_Current_page(&$res) { + if ($res['ArgumentCount'] != 0) throw new SSTemplateParseException('Current_page takes no arguments', $this); + return '$val .= $_SERVER[SCRIPT_URL];'; + } + + /* MismatchedEndBlock: '<%' < 'end_' !'$BlockName' :Word > '%>' */ + function match_MismatchedEndBlock ($substack = array()) { + $result = $this->construct( "MismatchedEndBlock" ); + $_293 = NULL; + do { + $_282 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_282->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_293 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_285 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_285->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_293 = FALSE; break; } + $res_288 = $result; + $pos_288 = $this->pos; + $_287 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_287->expand('$BlockName') ) ) !== FALSE) { + $result["text"] .= $subres; + $result = $res_288; + $this->pos = $pos_288; + $_293 = FALSE; break; + } + else { + $result = $res_288; + $this->pos = $pos_288; + } + $key = "Word"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Word" ); + } + else { $_293 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_291 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_291->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_293 = FALSE; break; } + $_293 = TRUE; break; + } + while(0); + if( $_293 === TRUE ) { + return $this->finalise( "MismatchedEndBlock", $result ); + } + if( $_293 === FALSE) { return FALSE; } + } + + + + function MismatchedEndBlock__finalise(&$res) { + $blockname = $res['Word']['text']; + throw new SSTemplateParseException('Unexpected close tag end_'.$blockname.' encountered. Perhaps you have mis-nested blocks, or have mis-spelled a tag?', $this); + } + + /* MalformedOpenTag: '<%' < !NotBlockTag Tag:Word !( ( [ :BlockArguments ] )? > '%>' ) */ + function match_MalformedOpenTag ($substack = array()) { + $result = $this->construct( "MalformedOpenTag" ); + $_310 = NULL; + do { + $_295 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_295->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_310 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $res_298 = $result; + $pos_298 = $this->pos; + $key = "NotBlockTag"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $result = $res_298; + $this->pos = $pos_298; + $_310 = FALSE; break; + } + else { + $result = $res_298; + $this->pos = $pos_298; + } + $key = "Word"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Tag" ); + } + else { $_310 = FALSE; break; } + $res_309 = $result; + $pos_309 = $this->pos; + $_308 = NULL; + do { + $res_304 = $result; + $pos_304 = $this->pos; + $_303 = NULL; + do { + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_303 = FALSE; break; } + $key = "BlockArguments"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "BlockArguments" ); + } + else { $_303 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_303 = FALSE; break; } + $_303 = TRUE; break; + } + while(0); + if( $_303 === FALSE) { + $result = $res_304; + $this->pos = $pos_304; + unset( $res_304 ); + unset( $pos_304 ); + } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_306 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_306->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_308 = FALSE; break; } + $_308 = TRUE; break; + } + while(0); + if( $_308 === TRUE ) { + $result = $res_309; + $this->pos = $pos_309; + $_310 = FALSE; break; + } + if( $_308 === FALSE) { + $result = $res_309; + $this->pos = $pos_309; + } + $_310 = TRUE; break; + } + while(0); + if( $_310 === TRUE ) { + return $this->finalise( "MalformedOpenTag", $result ); + } + if( $_310 === FALSE) { return FALSE; } + } + + + + function MalformedOpenTag__finalise(&$res) { + $tag = $res['Tag']['text']; + throw new SSTemplateParseException("Malformed opening block tag $tag. Perhaps you have tried to use operators?", $this); + } + + /* MalformedCloseTag: '<%' < Tag:('end_' :Word ) !( > '%>' ) */ + function match_MalformedCloseTag ($substack = array()) { + $result = $this->construct( "MalformedCloseTag" ); + $_326 = NULL; + do { + $_312 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_312->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_326 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $substack[] = $result; + $result = $this->construct( "Tag" ); + $_318 = NULL; + do { + $_315 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_315->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_318 = FALSE; break; } + $key = "Word"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Word" ); + } + else { $_318 = FALSE; break; } + $_318 = TRUE; break; + } + while(0); + if( $_318 === TRUE ) { + $subres = $result ; + $result = array_pop( $substack ) ; + $this->store( $result, $subres, 'Tag' ); + } + if( $_318 === FALSE) { + $result = array_pop( $substack ) ; + $_326 = FALSE; break; + } + $res_325 = $result; + $pos_325 = $this->pos; + $_324 = NULL; + do { + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_322 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_322->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_324 = FALSE; break; } + $_324 = TRUE; break; + } + while(0); + if( $_324 === TRUE ) { + $result = $res_325; + $this->pos = $pos_325; + $_326 = FALSE; break; + } + if( $_324 === FALSE) { + $result = $res_325; + $this->pos = $pos_325; + } + $_326 = TRUE; break; + } + while(0); + if( $_326 === TRUE ) { + return $this->finalise( "MalformedCloseTag", $result ); + } + if( $_326 === FALSE) { return FALSE; } + } + + + + function MalformedCloseTag__finalise(&$res) { + $tag = $res['Tag']['text']; + throw new SSTemplateParseException("Malformed closing block tag $tag. Perhaps you have tried to pass an argument to one?", $this); + } + + /* MalformedBlock: MalformedOpenTag | MalformedCloseTag */ + function match_MalformedBlock ($substack = array()) { + $result = $this->construct( "MalformedBlock" ); + $_331 = NULL; + do { + $res_328 = $result; + $pos_328 = $this->pos; + $key = "MalformedOpenTag"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedOpenTag(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_331 = TRUE; break; + } + $result = $res_328; + $this->pos = $pos_328; + $key = "MalformedCloseTag"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedCloseTag(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_331 = TRUE; break; + } + $result = $res_328; + $this->pos = $pos_328; + $_331 = FALSE; break; + } + while(0); + if( $_331 === TRUE ) { + return $this->finalise( "MalformedBlock", $result ); + } + if( $_331 === FALSE) { return FALSE; } + } + + + + + /* Comment: "<%--" (!"--%>" /./)+ "--%>" */ + function match_Comment ($substack = array()) { + $result = $this->construct( "Comment" ); + $_343 = NULL; + do { + $_333 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_333->expand("<%--") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_343 = FALSE; break; } + $count = 0; + while (true) { + $res_340 = $result; + $pos_340 = $this->pos; + $_339 = NULL; + do { + $res_336 = $result; + $pos_336 = $this->pos; + $_335 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_335->expand("--%>") ) ) !== FALSE) { + $result["text"] .= $subres; + $result = $res_336; + $this->pos = $pos_336; + $_339 = FALSE; break; + } + else { + $result = $res_336; + $this->pos = $pos_336; + } + $_337 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_337->expand('/./') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_339 = FALSE; break; } + $_339 = TRUE; break; + } + while(0); + if( $_339 === FALSE) { + $result = $res_340; + $this->pos = $pos_340; + unset( $res_340 ); + unset( $pos_340 ); + break; + } + $count += 1; + } + if ($count > 0) { } + else { $_343 = FALSE; break; } + $_341 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_341->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_343 = FALSE; break; } + $_343 = TRUE; break; + } + while(0); + if( $_343 === TRUE ) { + return $this->finalise( "Comment", $result ); + } + if( $_343 === FALSE) { return FALSE; } + } + + + + function Comment__construct(&$res) { + $res['php'] = ''; + } + + /* Text: / +( +(\\.) | # Any escaped character +([^<${]) | # Any character that isn't <, $ or { +(<[^%]) | # < if not followed by % +($[^A-Za-z_]) | # $ if not followed by A-Z, a-z or _ +({[^$]) | # { if not followed by $ +({$[^A-Za-z_]) # {$ if not followed A-Z, a-z or _ +)+ +/ */ + function match_Text ($substack = array()) { + $result = array("name"=>"Text", "text"=>""); + $_345 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_345->expand('/ +( +(\\\\.) | # Any escaped character +([^<${]) | # Any character that isn\'t <, $ or { +(<[^%]) | # < if not followed by % +($[^A-Za-z_]) | # $ if not followed by A-Z, a-z or _ +({[^$]) | # { if not followed by $ +({$[^A-Za-z_]) # {$ if not followed A-Z, a-z or _ +)+ +/') ) ) !== FALSE) { + $result["text"] .= $subres; + return $result; + } + else { return FALSE; } + } + + + /* Template: (Comment | If | Require | ClosedBlock | OpenBlock | MalformedBlock | Injection | Text)+ */ + function match_Template ($substack = array()) { + $result = $this->construct( "Template" ); + $count = 0; + while (true) { + $res_377 = $result; + $pos_377 = $this->pos; + $_376 = NULL; + do { + $_374 = NULL; + do { + $res_347 = $result; + $pos_347 = $this->pos; + $key = "Comment"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comment(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_374 = TRUE; break; + } + $result = $res_347; + $this->pos = $pos_347; + $_372 = NULL; + do { + $res_349 = $result; + $pos_349 = $this->pos; + $key = "If"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_If(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_372 = TRUE; break; + } + $result = $res_349; + $this->pos = $pos_349; + $_370 = NULL; + do { + $res_351 = $result; + $pos_351 = $this->pos; + $key = "Require"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Require(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_370 = TRUE; break; + } + $result = $res_351; + $this->pos = $pos_351; + $_368 = NULL; + do { + $res_353 = $result; + $pos_353 = $this->pos; + $key = "ClosedBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_368 = TRUE; break; + } + $result = $res_353; + $this->pos = $pos_353; + $_366 = NULL; + do { + $res_355 = $result; + $pos_355 = $this->pos; + $key = "OpenBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_366 = TRUE; break; + } + $result = $res_355; + $this->pos = $pos_355; + $_364 = NULL; + do { + $res_357 = $result; + $pos_357 = $this->pos; + $key = "MalformedBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_364 = TRUE; break; + } + $result = $res_357; + $this->pos = $pos_357; + $_362 = NULL; + do { + $res_359 = $result; + $pos_359 = $this->pos; + $key = "Injection"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_362 = TRUE; break; + } + $result = $res_359; + $this->pos = $pos_359; + $key = "Text"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_362 = TRUE; break; + } + $result = $res_359; + $this->pos = $pos_359; + $_362 = FALSE; break; + } + while(0); + if( $_362 === TRUE ) { $_364 = TRUE; break; } + $result = $res_357; + $this->pos = $pos_357; + $_364 = FALSE; break; + } + while(0); + if( $_364 === TRUE ) { $_366 = TRUE; break; } + $result = $res_355; + $this->pos = $pos_355; + $_366 = FALSE; break; + } + while(0); + if( $_366 === TRUE ) { $_368 = TRUE; break; } + $result = $res_353; + $this->pos = $pos_353; + $_368 = FALSE; break; + } + while(0); + if( $_368 === TRUE ) { $_370 = TRUE; break; } + $result = $res_351; + $this->pos = $pos_351; + $_370 = FALSE; break; + } + while(0); + if( $_370 === TRUE ) { $_372 = TRUE; break; } + $result = $res_349; + $this->pos = $pos_349; + $_372 = FALSE; break; + } + while(0); + if( $_372 === TRUE ) { $_374 = TRUE; break; } + $result = $res_347; + $this->pos = $pos_347; + $_374 = FALSE; break; + } + while(0); + if( $_374 === FALSE) { $_376 = FALSE; break; } + $_376 = TRUE; break; + } + while(0); + if( $_376 === FALSE) { + $result = $res_377; + $this->pos = $pos_377; + unset( $res_377 ); + unset( $pos_377 ); + break; + } + $count += 1; + } + if ($count > 0) { + return $this->finalise( "Template", $result ); + } + else { return FALSE; } + } + + + + function Template__construct(&$res) { + $res['php'] = ''; + } + + function Template_Text(&$res, $sub) { + $text = $sub['text']; + $text = preg_replace( + '/href\s*\=\s*\"\#/', + 'href="#', + $text + ); + + // TODO: using heredocs means any left over $ symbols will trigger PHP lookups, as will any escapes + // Will it break backwards compatibility to use ' quoted strings, and escape just the ' characters? + + $res['php'] .= + '$val .= <<construct( "TopTemplate" ); + $count = 0; + while (true) { + $res_412 = $result; + $pos_412 = $this->pos; + $_411 = NULL; + do { + $_409 = NULL; + do { + $res_378 = $result; + $pos_378 = $this->pos; + $key = "Comment"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comment(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_409 = TRUE; break; + } + $result = $res_378; + $this->pos = $pos_378; + $_407 = NULL; + do { + $res_380 = $result; + $pos_380 = $this->pos; + $key = "If"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_If(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_407 = TRUE; break; + } + $result = $res_380; + $this->pos = $pos_380; + $_405 = NULL; + do { + $res_382 = $result; + $pos_382 = $this->pos; + $key = "Require"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Require(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_405 = TRUE; break; + } + $result = $res_382; + $this->pos = $pos_382; + $_403 = NULL; + do { + $res_384 = $result; + $pos_384 = $this->pos; + $key = "ClosedBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_403 = TRUE; break; + } + $result = $res_384; + $this->pos = $pos_384; + $_401 = NULL; + do { + $res_386 = $result; + $pos_386 = $this->pos; + $key = "OpenBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_401 = TRUE; break; + } + $result = $res_386; + $this->pos = $pos_386; + $_399 = NULL; + do { + $res_388 = $result; + $pos_388 = $this->pos; + $key = "MalformedBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_399 = TRUE; break; + } + $result = $res_388; + $this->pos = $pos_388; + $_397 = NULL; + do { + $res_390 = $result; + $pos_390 = $this->pos; + $key = "MismatchedEndBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MismatchedEndBlock(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_397 = TRUE; break; + } + $result = $res_390; + $this->pos = $pos_390; + $_395 = NULL; + do { + $res_392 = $result; + $pos_392 = $this->pos; + $key = "Injection"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_395 = TRUE; break; + } + $result = $res_392; + $this->pos = $pos_392; + $key = "Text"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_395 = TRUE; break; + } + $result = $res_392; + $this->pos = $pos_392; + $_395 = FALSE; break; + } + while(0); + if( $_395 === TRUE ) { $_397 = TRUE; break; } + $result = $res_390; + $this->pos = $pos_390; + $_397 = FALSE; break; + } + while(0); + if( $_397 === TRUE ) { $_399 = TRUE; break; } + $result = $res_388; + $this->pos = $pos_388; + $_399 = FALSE; break; + } + while(0); + if( $_399 === TRUE ) { $_401 = TRUE; break; } + $result = $res_386; + $this->pos = $pos_386; + $_401 = FALSE; break; + } + while(0); + if( $_401 === TRUE ) { $_403 = TRUE; break; } + $result = $res_384; + $this->pos = $pos_384; + $_403 = FALSE; break; + } + while(0); + if( $_403 === TRUE ) { $_405 = TRUE; break; } + $result = $res_382; + $this->pos = $pos_382; + $_405 = FALSE; break; + } + while(0); + if( $_405 === TRUE ) { $_407 = TRUE; break; } + $result = $res_380; + $this->pos = $pos_380; + $_407 = FALSE; break; + } + while(0); + if( $_407 === TRUE ) { $_409 = TRUE; break; } + $result = $res_378; + $this->pos = $pos_378; + $_409 = FALSE; break; + } + while(0); + if( $_409 === FALSE) { $_411 = FALSE; break; } + $_411 = TRUE; break; + } + while(0); + if( $_411 === FALSE) { + $result = $res_412; + $this->pos = $pos_412; + unset( $res_412 ); + unset( $pos_412 ); + break; + } + $count += 1; + } + if ($count > 0) { + return $this->finalise( "TopTemplate", $result ); + } + else { return FALSE; } + } + + + + function TopTemplate__construct(&$res) { + $res['php'] = "Template_Text($res, $sub); } + function TopTemplate_STR(&$res, $sub) { return $this->Template_STR($res, $sub); } + + static function compileString($string, $templateName = "", $includeDebuggingComments=false) { + $parser = new SSTemplateParser($string); + $parser->includeDebuggingComments = $includeDebuggingComments; + + // Ignore UTF8 BOM at begining of string. TODO: Confirm this is needed, make sure SSViewer handles UTF (and other encodings) properly + if(substr($string, 0,3) == pack("CCC", 0xef, 0xbb, 0xbf)) $parser->pos = 3; + + $result = $parser->match_TopTemplate(); + if(!$result) throw new SSTemplateParseException('Unexpected problem parsing template', $parser); + + $code = $result['php']; + + if($includeDebuggingComments && $templateName && stripos($code, "]*>)/i', "\\1", $code); + $code = preg_replace('/(<\/html[^>]*>)/i', "\\1", $code); + } else { + $code = "\n" . $code . "\n"; + } + } + + return $code; + } + + static function compileFile($template) { + return self::compileString(file_get_contents($template)); + } +} diff --git a/core/SSTemplateParser.php.inc b/core/SSTemplateParser.php.inc new file mode 100644 index 000000000..7fd229833 --- /dev/null +++ b/core/SSTemplateParser.php.inc @@ -0,0 +1,503 @@ + + $Iteration + Partial cache blocks + i18n - we dont support then deprecated _t() or sprintf(_t()) methods; or the new <% t %> block yet + Add with and loop blocks + Add Up and Top + More error detection? + +This comment will not appear in the output +*/ + +// We want this to work when run by hand too +if (defined(THIRDPARTY_PATH)) { + require THIRDPARTY_PATH . '/php-peg/Parser.php' ; +} +else { + $base = dirname(__FILE__); + require $base.'/../thirdparty/php-peg/Parser.php'; +} + +/** +This is the exception raised when failing to parse a template. Note that we don't currently do any static analysis, so we can't know +if the template will run, just if it's malformed. It also won't catch mistakes that still look valid. +*/ +class SSTemplateParseException extends Exception { + + function __construct($message, $parser) { + $prior = substr($parser->string, 0, $parser->pos); + + preg_match_all('/\r\n|\r|\n/', $prior, $matches); + $line = count($matches[0])+1; + + parent::__construct("Parse error in template on line $line. Error was: $message"); + } + +} + +/** +This is the parser for the SilverStripe template language. It gets called on a string and uses a php-peg parser to match +that string against the language structure, building up the PHP code to execute that structure as it parses +*/ +class SSTemplateParser extends Parser { + + protected $includeDebuggingComments = false; + + function construct($name) { + $result = parent::construct($name); + $result['tags'] = array(); + return $result; + } + + function DLRBlockName() { + return '-none-'; + } + + /*!* SSTemplateParser + + Word: / [A-Za-z_] [A-Za-z0-9_]* / + Number: / [0-9]+ / + Value: / [A-Za-z0-9_]+ / + + Arguments: :Argument ( < "," < :Argument )* + */ + + /** Values are bare words in templates, but strings in PHP. We rely on PHP's type conversion to back-convert strings to numbers when needed */ + function Arguments_Argument(&$res, $sub) { + if (isset($res['php'])) $res['php'] .= ', '; + else $res['php'] = ''; + + $res['php'] .= ($sub['ArgumentMode'] == 'default') ? $sub['string_php'] : $sub['php']; + } + + /*!* + Call: Method:Word ( "(" < :Arguments? > ")" )? + + LookupStep: :Call &"." + LastLookupStep: :Call + + Lookup: LookupStep ("." LookupStep)* "." LastLookupStep | LastLookupStep + */ + + function Lookup__construct(&$res) { + $res['php'] = '$item'; + $res['LookupSteps'] = array(); + } + + function Lookup_AddLookupStep(&$res, $sub, $method) { + $res['LookupSteps'][] = $sub; + + $property = $sub['Call']['Method']['text']; + + if (isset($sub['Call']['Arguments']) && $arguments = $sub['Call']['Arguments']['php']) { + $res['php'] .= "->$method('$property', array($arguments), true)"; + } + else { + $res['php'] .= "->$method('$property', null, true)"; + } + } + + function Lookup_LookupStep(&$res, $sub) { + $this->Lookup_AddLookupStep($res, $sub, 'obj'); + } + + function Lookup_LastLookupStep(&$res, $sub) { + $this->Lookup_AddLookupStep($res, $sub, 'XML_val'); + } + + /*!* + SimpleInjection: '$' :Lookup + BracketInjection: '{$' :Lookup "}" + Injection: BracketInjection | SimpleInjection + */ + function Injection_STR(&$res, $sub) { + $res['php'] = '$val .= '. $sub['Lookup']['php'] . ';'; + } + + /*!* + DollarMarkedLookup: BracketInjection | SimpleInjection + */ + function DollarMarkedLookup_STR(&$res, $sub) { + $res['Lookup'] = $sub['Lookup']; + } + + /*!* + QuotedString: q:/['"]/ String:/ (\\\\ | \\. | [^$q\\])* / '$q' + + FreeString: /[^,)%!=|&]+/ + + Argument: + :DollarMarkedLookup | + :QuotedString | + :Lookup !(< FreeString)| + :FreeString + */ + function Argument_DollarMarkedLookup(&$res, $sub) { + $res['ArgumentMode'] = 'lookup'; + $res['php'] = $sub['Lookup']['php']; + } + + function Argument_QuotedString(&$res, $sub) { + $res['ArgumentMode'] = 'string'; + $res['php'] = "'" . $sub['String']['text'] . "'"; + } + + function Argument_Lookup(&$res, $sub) { + if (count($sub['LookupSteps']) == 1 && !isset($sub['LookupSteps'][0]['Call']['Arguments'])) { + $res['ArgumentMode'] = 'default'; + $res['lookup_php'] = $sub['php']; + $res['string_php'] = "'".$sub['LookupSteps'][0]['Call']['Method']['text']."'"; + } + else { + $res['ArgumentMode'] = 'lookup'; + $res['php'] = $sub['php']; + } + } + + function Argument_FreeString(&$res, $sub) { + $res['ArgumentMode'] = 'string'; + $res['php'] = "'" . $sub['text'] . "'"; + } + + /*!* + ComparisonOperator: "==" | "!=" | "=" + + Comparison: Argument < ComparisonOperator > Argument + */ + function Comparison_Argument(&$res, $sub) { + if ($sub['ArgumentMode'] == 'default') { + if (isset($res['php'])) $res['php'] .= $sub['string_php']; + else $res['php'] = $sub['lookup_php']; + } + else { + if (!isset($res['php'])) $res['php'] = ''; + $res['php'] .= $sub['php']; + } + } + + function Comparison_ComparisonOperator(&$res, $sub) { + $res['php'] .= ($sub['text'] == '=' ? '==' : $sub['text']); + } + + /*!* + PresenceCheck: Argument + */ + function PresenceCheck_Argument(&$res, $sub) { + if ($sub['ArgumentMode'] == 'string') { + $res['php'] = '((bool)'.$sub['php'].')'; + } + else { + $php = ($sub['ArgumentMode'] == 'default' ? $sub['lookup_php'] : $sub['php']); + // TODO: kinda hacky - maybe we need a way to pass state down the parse chain so + // Lookup_LastLookupStep and Argument_BareWord can produce hasValue instead of XML_val + $res['php'] = str_replace('->XML_val', '->hasValue', $php); + } + } + + /*!* + IfArgumentPortion: Comparison | PresenceCheck + */ + function IfArgumentPortion_STR(&$res, $sub) { + $res['php'] = $sub['php']; + } + + /*!* + BooleanOperator: "||" | "&&" + + IfArgument: :IfArgumentPortion ( < :BooleanOperator < :IfArgumentPortion )* + */ + function IfArgument__construct(&$res){ + $res['php'] = ''; + } + function IfArgument_IfArgumentPortion(&$res, $sub) { + $res['php'] .= $sub['php']; + } + + function IfArgument_BooleanOperator(&$res, $sub) { + $res['php'] .= $sub['text']; + } + + /*!* + IfPart: '<%' < 'if' < :IfArgument > '%>' :Template? + ElseIfPart: '<%' < 'else_if' < :IfArgument > '%>' :Template? + ElsePart: '<%' < 'else' > '%>' :Template? + + If: IfPart ElseIfPart* ElsePart? '<%' < 'end_if' > '%>' + */ + function If__construct(&$res) { + $res['BlockName'] = 'if'; + } + + function If_IfPart(&$res, $sub) { + $res['php'] = + 'if (' . $sub['IfArgument']['php'] . ') { ' . PHP_EOL . + $sub['Template']['php'] . PHP_EOL . + '}'; + } + + function If_ElseIfPart(&$res, $sub) { + $res['php'] .= + 'else if (' . $sub['IfArgument']['php'] . ') { ' . PHP_EOL . + $sub['Template']['php'] . PHP_EOL . + '}'; + } + + function If_ElsePart(&$res, $sub) { + $res['php'] .= + 'else { ' . PHP_EOL . + $sub['Template']['php'] . PHP_EOL . + '}'; + } + + /*!* + Require: '<%' < 'require' [ Call:(Method:Word "(" < :Arguments > ")") > '%>' + */ + function Require_Call(&$res, $sub) { + $res['php'] = "Requirements::".$sub['Method']['text'].'('.$sub['Arguments']['php'].');'; + } + + /*!* + BlockArguments: :Argument ( < "," < :Argument)* + + NotBlockTag: "end_" | (("if" | "else_if" | "else" | "require") ] ) + + ClosedBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > Zap:'%>' :Template? '<%' < 'end_' '$BlockName' > '%>' + */ + function ClosedBlock__construct(&$res) { + $res['ArgumentCount'] = 0; + } + + function ClosedBlock_BlockArguments(&$res, $sub) { + if (isset($sub['Argument']['ArgumentMode'])) { + $res['Arguments'] = array($sub['Argument']); + $res['ArgumentCount'] = 1; + } + else { + $res['Arguments'] = $sub['Argument']; + $res['ArgumentCount'] = count($res['Arguments']); + } + } + + function ClosedBlock__finalise(&$res) { + $blockname = $res['BlockName']['text']; + + $method = 'ClosedBlock_Handle_'.ucfirst(strtolower($blockname)); + if (method_exists($this, $method)) $res['php'] = $this->$method($res); + else { + throw new SSTemplateParseException('Unknown closed block "'.$blockname.'" encountered. Perhaps you are not supposed to close this block, or have mis-spelled it?', $this); + } + } + + function ClosedBlock_Handle_Control(&$res) { + if ($res['ArgumentCount'] != 1) { + throw new SSTemplateParseException('Either no or too many arguments in control block. Must be one argument only.', $this); + } + + $arg = $res['Arguments'][0]; + if ($arg['ArgumentMode'] == 'string') { + throw new SSTemplateParseException('Control block cant take string as argument.', $this); + } + + $on = str_replace('->XML_val', '->obj', ($arg['ArgumentMode'] == 'default') ? $arg['lookup_php'] : $arg['php']); + return + 'array_push($itemStack, $item); if($loop = '.$on.') foreach($loop as $key => $item) {' . PHP_EOL . + $res['Template']['php'] . PHP_EOL . + '} $item = array_pop($itemStack); '; + } + + /*!* + OpenBlock: '<%' < !NotBlockTag OpenBlockName:Word ( [ :BlockArguments ] )? > '%>' + */ + function OpenBlock__construct(&$res) { + $res['ArgumentCount'] = 0; + } + + function OpenBlock_BlockArguments(&$res, $sub) { + if (isset($sub['Argument']['ArgumentMode'])) { + $res['Arguments'] = array($sub['Argument']); + $res['ArgumentCount'] = 1; + } + else { + $res['Arguments'] = $sub['Argument']; + $res['ArgumentCount'] = count($res['Arguments']); + } + } + + function OpenBlock__finalise(&$res) { + $blockname = $res['OpenBlockName']['text']; + + $method = 'OpenBlock_Handle_'.ucfirst(strtolower($blockname)); + if (method_exists($this, $method)) $res['php'] = $this->$method($res); + else { + throw new SSTemplateParseException('Unknown open block "'.$blockname.'" encountered. Perhaps you missed the closing tag or have mis-spelled it?', $this); + } + } + + function OpenBlock_Handle_Include(&$res) { + if ($res['ArgumentCount'] != 1) throw new SSTemplateParseException('Include takes exactly one argument', $this); + + $arg = $res['Arguments'][0]; + $php = ($arg['ArgumentMode'] == 'default') ? $arg['string_php'] : $arg['php']; + + if($this->includeDebuggingComments) { // Add include filename comments on dev sites + return + '$val .= \'\';'. "\n". + '$val .= SSViewer::parse_template('.$php.', $item);'. "\n". + '$val .= \'\';'. "\n"; + } + else { + return + '$val .= SSViewer::execute_template('.$php.', $item);'. "\n"; + } + } + + function OpenBlock_Handle_Debug(&$res) { + if ($res['ArgumentCount'] == 0) return 'Debug::show($item);'; + else if ($res['ArgumentCount'] == 1) { + $arg = $res['Arguments'][0]; + + if ($arg['ArgumentMode'] == 'string') return 'Debug::show('.$arg['php'].');'; + + $php = ($arg['ArgumentMode'] == 'default') ? $arg['lookup_php'] : $arg['php']; + return '$val .= Debug::show('.str_replace('FINALGET!', 'cachedCall', $php).');'; + } + else { + throw new SSTemplateParseException('Debug takes 0 or 1 argument only.', $this); + } + } + + function OpenBlock_Handle_Base_tag(&$res) { + if ($res['ArgumentCount'] != 0) throw new SSTemplateParseException('Base_tag takes no arguments', $this); + return '$val .= SSViewer::get_base_tag($val);'; + } + + function OpenBlock_Handle_Current_page(&$res) { + if ($res['ArgumentCount'] != 0) throw new SSTemplateParseException('Current_page takes no arguments', $this); + return '$val .= $_SERVER[SCRIPT_URL];'; + } + + /*!* + MismatchedEndBlock: '<%' < 'end_' !'$BlockName' :Word > '%>' + */ + function MismatchedEndBlock__finalise(&$res) { + $blockname = $res['Word']['text']; + throw new SSTemplateParseException('Unexpected close tag end_'.$blockname.' encountered. Perhaps you have mis-nested blocks, or have mis-spelled a tag?', $this); + } + + /*!* + MalformedOpenTag: '<%' < !NotBlockTag Tag:Word !( ( [ :BlockArguments ] )? > '%>' ) + */ + function MalformedOpenTag__finalise(&$res) { + $tag = $res['Tag']['text']; + throw new SSTemplateParseException("Malformed opening block tag $tag. Perhaps you have tried to use operators?", $this); + } + + /*!* + MalformedCloseTag: '<%' < Tag:('end_' :Word ) !( > '%>' ) + */ + function MalformedCloseTag__finalise(&$res) { + $tag = $res['Tag']['text']; + throw new SSTemplateParseException("Malformed closing block tag $tag. Perhaps you have tried to pass an argument to one?", $this); + } + + /*!* + MalformedBlock: MalformedOpenTag | MalformedCloseTag + */ + + /*!* + Comment: "<%--" (!"--%>" /./)+ "--%>" + */ + function Comment__construct(&$res) { + $res['php'] = ''; + } + + /*!* + Text: / + ( + (\\.) | # Any escaped character + ([^<${]) | # Any character that isn't <, $ or { + (<[^%]) | # < if not followed by % + ($[^A-Za-z_]) | # $ if not followed by A-Z, a-z or _ + ({[^$]) | # { if not followed by $ + ({$[^A-Za-z_]) # {$ if not followed A-Z, a-z or _ + )+ + / + + Template: (Comment | If | Require | ClosedBlock | OpenBlock | MalformedBlock | Injection | Text)+ + */ + function Template__construct(&$res) { + $res['php'] = ''; + } + + function Template_Text(&$res, $sub) { + $text = $sub['text']; + $text = preg_replace( + '/href\s*\=\s*\"\#/', + 'href="#', + $text + ); + + // TODO: using heredocs means any left over $ symbols will trigger PHP lookups, as will any escapes + // Will it break backwards compatibility to use ' quoted strings, and escape just the ' characters? + + $res['php'] .= + '$val .= <<Template_Text($res, $sub); } + function TopTemplate_STR(&$res, $sub) { return $this->Template_STR($res, $sub); } + + static function compileString($string, $templateName = "", $includeDebuggingComments=false) { + $parser = new SSTemplateParser($string); + $parser->includeDebuggingComments = $includeDebuggingComments; + + // Ignore UTF8 BOM at begining of string. TODO: Confirm this is needed, make sure SSViewer handles UTF (and other encodings) properly + if(substr($string, 0,3) == pack("CCC", 0xef, 0xbb, 0xbf)) $parser->pos = 3; + + $result = $parser->match_TopTemplate(); + if(!$result) throw new SSTemplateParseException('Unexpected problem parsing template', $parser); + + $code = $result['php']; + + if($includeDebuggingComments && $templateName && stripos($code, "]*>)/i', "\\1", $code); + $code = preg_replace('/(<\/html[^>]*>)/i', "\\1", $code); + } else { + $code = "\n" . $code . "\n"; + } + } + + return $code; + } + + static function compileFile($template) { + return self::compileString(file_get_contents($template)); + } +} From f6587c4ea2f1a6eeac1bcb7a8246cdaa40fe01c7 Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Thu, 10 Feb 2011 17:39:31 +1300 Subject: [PATCH 03/15] ENHANCEMENT: Use the new SSTemplateParser class to compile the templates --- core/SSViewer.php | 169 +--------------------------------------------- 1 file changed, 1 insertion(+), 168 deletions(-) diff --git a/core/SSViewer.php b/core/SSViewer.php index 4e5f8194f..56dcbe00a 100755 --- a/core/SSViewer.php +++ b/core/SSViewer.php @@ -460,174 +460,7 @@ class SSViewer { } static function parseTemplateContent($content, $template="") { - // Remove UTF-8 byte order mark: - // This is only necessary if you don't have zend-multibyte enabled. - if(substr($content, 0,3) == pack("CCC", 0xef, 0xbb, 0xbf)) { - $content = substr($content, 3); - } - - // Add template filename comments on dev sites - if(Director::isDev() && self::$source_file_comments && $template && stripos($content, "]*>)/i', "\\1", $content); - $content = preg_replace('/(<\/html[^>]*>)/i', "\\1", $content); - } else { - $content = "\n" . $content . "\n"; - } - } - - // $val, $val.property, $val(param), etc. - $replacements = array( - '/<%--.*--%>/U' => '', - '/\$Iteration/' => '', - '/{\\$([A-Za-z_][A-Za-z0-9_]*)\\(([^),]+), *([^),]+)\\)\\.([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+)}/' => 'obj("\\1",array("\\2","\\3"),true)->obj("\\4",null,true)->XML_val("\\5",null,true) ?>', - '/{\\$([A-Za-z_][A-Za-z0-9_]*)\\(([^),]+), *([^),]+)\\)\\.([A-Za-z0-9_]+)}/' => 'obj("\\1",array("\\2","\\3"),true)->XML_val("\\4",null,true) ?>', - '/{\\$([A-Za-z_][A-Za-z0-9_]*)\\(([^),]+), *([^),]+)\\)}/' => 'XML_val("\\1",array("\\2","\\3"),true) ?>', - '/{\\$([A-Za-z_][A-Za-z0-9_]*)\\(([^),]+)\\)\\.([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+)}/' => 'obj("\\1",array("\\2"),true)->obj("\\3",null,true)->XML_val("\\4",null,true) ?>', - '/{\\$([A-Za-z_][A-Za-z0-9_]*)\\(([^),]+)\\)\\.([A-Za-z0-9_]+)}/' => 'obj("\\1",array("\\2"),true)->XML_val("\\3",null,true) ?>', - '/{\\$([A-Za-z_][A-Za-z0-9_]*)\\(([^),]+)\\)}/' => 'XML_val("\\1",array("\\2"),true) ?>', - '/{\\$([A-Za-z_][A-Za-z0-9_]*)\\.([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+)}/' => 'obj("\\1",null,true)->obj("\\2",null,true)->XML_val("\\3",null,true) ?>', - '/{\\$([A-Za-z_][A-Za-z0-9_]*)\\.([A-Za-z0-9_]+)}/' => 'obj("\\1",null,true)->XML_val("\\2",null,true) ?>', - '/{\\$([A-Za-z_][A-Za-z0-9_]*)}/' => 'XML_val("\\1",null,true) ?>\\2', - - '/\\$([A-Za-z_][A-Za-z0-9_]*)\\.([A-Za-z0-9_]+)\\(([^),]+)\\)([^A-Za-z0-9]|$)/' => 'obj("\\1")->XML_val("\\2",array("\\3"),true) ?>\\4', - '/\\$([A-Za-z_][A-Za-z0-9_]*)\\.([A-Za-z0-9_]+)\\(([^),]+), *([^),]+)\\)([^A-Za-z0-9]|$)/' => 'obj("\\1")->XML_val("\\2",array("\\3", "\\4"),true) ?>\\5', - - '/\\$([A-Za-z_][A-Za-z0-9_]*)\\(([^),]+), *([^),]+)\\)\\.([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+)([^A-Za-z0-9]|$)/' => 'obj("\\1",array("\\2","\\3"),true)->obj("\\4",null,true)->XML_val("\\5",null,true) ?>\\6', - '/\\$([A-Za-z_][A-Za-z0-9_]*)\\(([^),]+), *([^),]+)\\)\\.([A-Za-z0-9_]+)([^A-Za-z0-9]|$)/' => 'obj("\\1",array("\\2","\\3"),true)->XML_val("\\4",null,true) ?>\\5', - '/\\$([A-Za-z_][A-Za-z0-9_]*)\\(([^),]+), *([^),]+)\\)([^A-Za-z0-9]|$)/' => 'XML_val("\\1",array("\\2","\\3"),true) ?>\\4', - '/\\$([A-Za-z_][A-Za-z0-9_]*)\\(([^),]+)\\)\\.([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+)([^A-Za-z0-9]|$)/' => 'obj("\\1",array("\\2"),true)->obj("\\3",null,true)->XML_val("\\4",null,true) ?>\\5', - '/\\$([A-Za-z_][A-Za-z0-9_]*)\\(([^),]+)\\)\\.([A-Za-z0-9_]+)([^A-Za-z0-9]|$)/' => 'obj("\\1",array("\\2"),true)->XML_val("\\3",null,true) ?>\\4', - '/\\$([A-Za-z_][A-Za-z0-9_]*)\\(([^),]+)\\)([^A-Za-z0-9]|$)/' => 'XML_val("\\1",array("\\2"),true) ?>\\3', - '/\\$([A-Za-z_][A-Za-z0-9_]*)\\.([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+)([^A-Za-z0-9]|$)/' => 'obj("\\1",null,true)->obj("\\2",null,true)->XML_val("\\3",null,true) ?>\\4', - '/\\$([A-Za-z_][A-Za-z0-9_]*)\\.([A-Za-z0-9_]+)([^A-Za-z0-9]|$)/' => 'obj("\\1",null,true)->XML_val("\\2",null,true) ?>\\3', - '/\\$([A-Za-z_][A-Za-z0-9_]*)([^A-Za-z0-9]|$)/' => 'XML_val("\\1",null,true) ?>\\2', - ); - - $content = preg_replace(array_keys($replacements), array_values($replacements), $content); - $content = str_replace('{dlr}','$',$content); - - // Cache block - $content = SSViewer_PartialParser::process($template, $content); - - // legacy - $content = ereg_replace('', '<' . '% control \\1 %' . '>', $content); - $content = ereg_replace('', '<' . '% end_control %' . '>', $content); - - // < % control Foo % > - $content = ereg_replace('<' . '% +control +([A-Za-z0-9_]+) +%' . '>', 'obj("\\1")) foreach($loop as $key => $item) { ?>', $content); - // < % control Foo.Bar % > - $content = ereg_replace('<' . '% +control +([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+) +%' . '>', 'obj("\\1")) && ($loop = $loop->obj("\\2"))) foreach($loop as $key => $item) { ?>', $content); - // < % control Foo.Bar(Baz) % > - $content = ereg_replace('<' . '% +control +([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+)\\(([^),]+)\\) +%' . '>', 'obj("\\1")) && ($loop = $loop->obj("\\2", array("\\3")))) foreach($loop as $key => $item) { ?>', $content); - // < % control Foo(Bar) % > - $content = ereg_replace('<' . '% +control +([A-Za-z0-9_]+)\\(([^),]+)\\) +%' . '>', 'obj("\\1", array("\\2"))) foreach($loop as $key => $item) { ?>', $content); - // < % control Foo(Bar, Baz) % > - $content = ereg_replace('<' . '% +control +([A-Za-z0-9_]+)\\(([^),]+), *([^),]+)\\) +%' . '>', 'obj("\\1", array("\\2","\\3"))) foreach($loop as $key => $item) { ?>', $content); - // < % control Foo(Bar, Baz, Buz) % > - $content = ereg_replace('<' . '% +control +([A-Za-z0-9_]+)\\(([^),]+), *([^),]+), *([^),]+)\\) +%' . '>', 'obj("\\1", array("\\2", "\\3", "\\4"))) foreach($loop as $key => $item) { ?>', $content); - $content = ereg_replace('<' . '% +end_control +%' . '>', '', $content); - $content = ereg_replace('<' . '% +debug +%' . '>', '', $content); - $content = ereg_replace('<' . '% +debug +([A-Za-z0-9_]+) +%' . '>', 'cachedCall("\\1")) ?>', $content); - - // < % if val1.property % > - $content = ereg_replace('<' . '% +if +([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+) +%' . '>', 'obj("\\1",null,true)->hasValue("\\2")) { ?>', $content); - - // < % if val1(parameter) % > - $content = ereg_replace('<' . '% +if +([A-Za-z0-9_]+)\\(([A-Za-z0-9_-]+)\\) +%' . '>', 'hasValue("\\1",array("\\2"))) { ?>', $content); - - // < % if val1 % > - $content = ereg_replace('<' . '% +if +([A-Za-z0-9_]+) +%' . '>', 'hasValue("\\1")) { ?>', $content); - $content = ereg_replace('<' . '% +else_if +([A-Za-z0-9_]+) +%' . '>', 'hasValue("\\1")) { ?>', $content); - - // < % if val1 || val2 % > - $content = ereg_replace('<' . '% +if +([A-Za-z0-9_]+) *\\|\\|? *([A-Za-z0-9_]+) +%' . '>', 'hasValue("\\1") || $item->hasValue("\\2")) { ?>', $content); - $content = ereg_replace('<' . '% +else_if +([A-Za-z0-9_]+) *\\|\\|? *([A-Za-z0-9_]+) +%' . '>', 'hasValue("\\1") || $item->hasValue("\\2")) { ?>', $content); - - // < % if val1 && val2 % > - $content = ereg_replace('<' . '% +if +([A-Za-z0-9_]+) *&&? *([A-Za-z0-9_]+) +%' . '>', 'hasValue("\\1") && $item->hasValue("\\2")) { ?>', $content); - $content = ereg_replace('<' . '% +else_if +([A-Za-z0-9_]+) *&&? *([A-Za-z0-9_]+) +%' . '>', 'hasValue("\\1") && $item->hasValue("\\2")) { ?>', $content); - - // < % if val1 == val2 % > - $content = ereg_replace('<' . '% +if +([A-Za-z0-9_]+) *==? *"?([A-Za-z0-9_-]+)"? +%' . '>', 'XML_val("\\1",null,true) == "\\2") { ?>', $content); - $content = ereg_replace('<' . '% +else_if +([A-Za-z0-9_]+) *==? *"?([A-Za-z0-9_-]+)"? +%' . '>', 'XML_val("\\1",null,true) == "\\2") { ?>', $content); - - // < % if val1 != val2 % > - $content = ereg_replace('<' . '% +if +([A-Za-z0-9_]+) *!= *"?([A-Za-z0-9_-]+)"? +%' . '>', 'XML_val("\\1",null,true) != "\\2") { ?>', $content); - $content = ereg_replace('<' . '% +else_if +([A-Za-z0-9_]+) *!= *"?([A-Za-z0-9_-]+)"? +%' . '>', 'XML_val("\\1",null,true) != "\\2") { ?>', $content); - - $content = ereg_replace('<' . '% +else_if +([A-Za-z0-9_]+) +%' . '>', 'cachedCall("\\1")) && ((!is_object($test) && $test) || ($test && $test->exists()) )) { ?>', $content); - - $content = ereg_replace('<' . '% +if +([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+) +%' . '>', 'obj("\\1",null,true)->cachedCall("\\2"); if((!is_object($test) && $test) || ($test && $test->exists())) { ?>', $content); - $content = ereg_replace('<' . '% +else_if +([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+) +%' . '>', 'obj("\\1",null,true)->cachedCall("\\2")) && ((!is_object($test) && $test) || ($test && $test->exists()) )) { ?>', $content); - - $content = ereg_replace('<' . '% +if +([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+) +%' . '>', 'obj("\\1",null,true)->obj("\\2",null,true)->cachedCall("\\3"); if((!is_object($test) && $test) || ($test && $test->exists())) { ?>', $content); - $content = ereg_replace('<' . '% +else_if +([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+)\\.([A-Za-z0-9_]+) +%' . '>', 'obj("\\1",null,true)->obj("\\2",null,true)->cachedCall("\\3")) && ((!is_object($test) && $test) || ($test && $test->exists()) )) { ?>', $content); - - $content = ereg_replace('<' . '% +else +%' . '>', '', $content); - $content = ereg_replace('<' . '% +end_if +%' . '>', '', $content); - - // i18n - get filename of currently parsed template - // CAUTION: No spaces allowed between arguments for all i18n calls! - ereg('.*[\/](.*)',$template,$path); - - // i18n _t(...) - with entity only (no dots in namespace), - // meaning the current template filename will be added as a namespace. - // This applies only to "root" templates, not includes which should always have their namespace set already. - // See getTemplateContent() for more information. - $content = ereg_replace('<' . '% +_t\((\'([^\.\']*)\'|"([^\."]*)")(([^)]|\)[^ ]|\) +[^% ])*)\) +%' . '>', '', $content); - // i18n _t(...) - $content = ereg_replace('<' . '% +_t\((\'([^\']*)\'|"([^"]*)")(([^)]|\)[^ ]|\) +[^% ])*)\) +%' . '>', '', $content); - - // i18n sprintf(_t(...),$argument) with entity only (no dots in namespace), meaning the current template filename will be added as a namespace - $content = ereg_replace('<' . '% +sprintf\(_t\((\'([^\.\']*)\'|"([^\."]*)")(([^)]|\)[^ ]|\) +[^% ])*)\),\<\?= +([^\?]*) +\?\>) +%' . '>', '', $content); - // i18n sprintf(_t(...),$argument) - $content = ereg_replace('<' . '% +sprintf\(_t\((\'([^\']*)\'|"([^"]*)")(([^)]|\)[^ ]|\) +[^% ])*)\),\<\?= +([^\?]*) +\?\>) +%' . '>', '', $content); - - // isnt valid html? !? - $content = ereg_replace('<' . '% +base_tag +%' . '>', '', $content); - - $content = ereg_replace('<' . '% +current_page +%' . '>', '', $content); - - // change < % require x() % > calls to corresponding Requirement::x() ones, including 0, 1 or 2 options - $content = preg_replace('/<% +require +([a-zA-Z]+)(?:\(([^),]+)\))? +%>/', '', $content); - $content = preg_replace('/<% +require +([a-zA-Z]+)\(([^),]+), *([^),]+)\) +%>/', '', $content); - - - // Add include filename comments on dev sites - if(Director::isDev() && self::$source_file_comments) $replacementCode = 'return "\n" - . "" - . "\n";'; - else $replacementCode = 'return "";'; - - $content = preg_replace_callback('/<' . '% include +([A-Za-z0-9_]+) +%' . '>/', create_function( - '$matches', $replacementCode - ), $content); - - // legacy - $content = ereg_replace('', 'cachedCall("\\1")) { ?>', $content); - $content = ereg_replace('', '', $content); - $content = ereg_replace('', '', $content); - - // Fix link stuff - $content = ereg_replace('href *= *"#', 'href="#', $content); - - // Protect xml header - $content = ereg_replace('<\?xml([^>]+)\?' . '>', '<##xml\\1##>', $content); - - // Turn PHP file into string definition - $content = str_replace('',";\n \$val .= <<]+)##>', '<' . '?xml\\1?' . '>', $output); - - return $output; + return SSTemplateParser::compileString($content, $template, Director::isDev() && self::$source_file_comments); } /** From cc4d23061e8702cb8734c1dd94aa1b08eb7985a1 Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Mon, 14 Feb 2011 14:10:17 +1300 Subject: [PATCH 04/15] ENHANCEMENT: Enable tests disabled in 2.4, as they all work now --- tests/SSViewerTest.php | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/tests/SSViewerTest.php b/tests/SSViewerTest.php index 1066e41b0..61cd8cee3 100644 --- a/tests/SSViewerTest.php +++ b/tests/SSViewerTest.php @@ -218,10 +218,8 @@ after') // Dot syntax $this->assertEquals('ACD', $this->render('A<% if Foo.NotSet %>B<% else_if Foo.IsSet %>C<% end_if %>D')); - - // Broken currently - //$this->assertEquals('ACD', - // $this->render('A<% if Foo.Bar.NotSet %>B<% else_if Foo.Bar.IsSet %>C<% end_if %>D')); + $this->assertEquals('ACD', + $this->render('A<% if Foo.Bar.NotSet %>B<% else_if Foo.Bar.IsSet %>C<% end_if %>D')); // Params $this->assertEquals('ACD', @@ -236,12 +234,10 @@ after') $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet %>C<% end_if %>D')); $this->assertEquals('AD', $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet3 %>C<% end_if %>D')); - - // Broken currently - //$this->assertEquals('ACD', - // $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet || NotSet %>C<% end_if %>D')); - //$this->assertEquals('AD', - // $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet2 || NotSet3 %>C<% end_if %>D')); + $this->assertEquals('ACD', + $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet || NotSet %>C<% end_if %>D')); + $this->assertEquals('AD', + $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet2 || NotSet3 %>C<% end_if %>D')); // And $this->assertEquals('ABD', @@ -250,12 +246,10 @@ after') $this->render('A<% if IsSet && NotSet %>B<% else_if IsSet %>C<% end_if %>D')); $this->assertEquals('AD', $this->render('A<% if NotSet && NotSet2 %>B<% else_if NotSet3 %>C<% end_if %>D')); - - // Broken currently - //$this->assertEquals('ACD', - // $this->render('A<% if IsSet && NotSet %>B<% else_if IsSet && AlsoSet %>C<% end_if %>D')); - //$this->assertEquals('AD', - // $this->render('A<% if NotSet && NotSet2 %>B<% else_if IsSet && NotSet3 %>C<% end_if %>D')); + $this->assertEquals('ACD', + $this->render('A<% if IsSet && NotSet %>B<% else_if IsSet && AlsoSet %>C<% end_if %>D')); + $this->assertEquals('AD', + $this->render('A<% if NotSet && NotSet2 %>B<% else_if IsSet && NotSet3 %>C<% end_if %>D')); // Equality $this->assertEquals('ABC', @@ -345,6 +339,7 @@ class SSViewerTestFixture extends ViewableData { function __construct($name = null) { $this->name = $name; + parent::__construct(); } From 67e4f8521afc94829c95f3330b994984f55638d4 Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Mon, 14 Feb 2011 16:52:01 +1300 Subject: [PATCH 05/15] BUGFIX: We dont try and detect mismatched end blocks except at the top level, so remove old redundant code from when we did --- core/SSTemplateParser.php | 627 ++++++++++++++++------------------ core/SSTemplateParser.php.inc | 14 +- 2 files changed, 305 insertions(+), 336 deletions(-) diff --git a/core/SSTemplateParser.php b/core/SSTemplateParser.php index 7d46acbb5..dd3c2e9c7 100644 --- a/core/SSTemplateParser.php +++ b/core/SSTemplateParser.php @@ -47,10 +47,6 @@ class SSTemplateParser extends Parser { return $result; } - function DLRBlockName() { - return '-none-'; - } - /* Word: / [A-Za-z_] [A-Za-z0-9_]* / */ function match_Word ($substack = array()) { $result = array("name"=>"Word", "text"=>""); @@ -1109,10 +1105,6 @@ class SSTemplateParser extends Parser { - function If__construct(&$res) { - $res['BlockName'] = 'if'; - } - function If_IfPart(&$res, $sub) { $res['php'] = 'if (' . $sub['IfArgument']['php'] . ') { ' . PHP_EOL . @@ -1499,7 +1491,7 @@ class SSTemplateParser extends Parser { '} $item = array_pop($itemStack); '; } - /* OpenBlock: '<%' < !NotBlockTag OpenBlockName:Word ( [ :BlockArguments ] )? > '%>' */ + /* OpenBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > '%>' */ function match_OpenBlock ($substack = array()) { $result = $this->construct( "OpenBlock" ); $_280 = NULL; @@ -1525,7 +1517,7 @@ class SSTemplateParser extends Parser { $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { - $this->store( $result, $subres, "OpenBlockName" ); + $this->store( $result, $subres, "BlockName" ); } else { $_280 = FALSE; break; } $res_276 = $result; @@ -1582,7 +1574,7 @@ class SSTemplateParser extends Parser { } function OpenBlock__finalise(&$res) { - $blockname = $res['OpenBlockName']['text']; + $blockname = $res['BlockName']['text']; $method = 'OpenBlock_Handle_'.ucfirst(strtolower($blockname)); if (method_exists($this, $method)) $res['php'] = $this->$method($res); @@ -1634,48 +1626,33 @@ class SSTemplateParser extends Parser { return '$val .= $_SERVER[SCRIPT_URL];'; } - /* MismatchedEndBlock: '<%' < 'end_' !'$BlockName' :Word > '%>' */ + /* MismatchedEndBlock: '<%' < 'end_' Word > '%>' */ function match_MismatchedEndBlock ($substack = array()) { $result = $this->construct( "MismatchedEndBlock" ); - $_293 = NULL; + $_291 = NULL; do { $_282 = new ParserExpression( $this, $substack, $result ); if (( $subres = $this->literal( $_282->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_293 = FALSE; break; } + else { $_291 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $_285 = new ParserExpression( $this, $substack, $result ); if (( $subres = $this->literal( $_285->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_293 = FALSE; break; } - $res_288 = $result; - $pos_288 = $this->pos; - $_287 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_287->expand('$BlockName') ) ) !== FALSE) { - $result["text"] .= $subres; - $result = $res_288; - $this->pos = $pos_288; - $_293 = FALSE; break; - } - else { - $result = $res_288; - $this->pos = $pos_288; - } + else { $_291 = FALSE; break; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres, "Word" ); - } - else { $_293 = FALSE; break; } + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_291 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_291 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_291->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_293 = FALSE; break; } - $_293 = TRUE; break; + $_289 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_289->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_291 = FALSE; break; } + $_291 = TRUE; break; } while(0); - if( $_293 === TRUE ) { + if( $_291 === TRUE ) { return $this->finalise( "MismatchedEndBlock", $result ); } - if( $_293 === FALSE) { return FALSE; } + if( $_291 === FALSE) { return FALSE; } } @@ -1688,82 +1665,82 @@ class SSTemplateParser extends Parser { /* MalformedOpenTag: '<%' < !NotBlockTag Tag:Word !( ( [ :BlockArguments ] )? > '%>' ) */ function match_MalformedOpenTag ($substack = array()) { $result = $this->construct( "MalformedOpenTag" ); - $_310 = NULL; + $_308 = NULL; do { - $_295 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_295->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_310 = FALSE; break; } + $_293 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_293->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_308 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_298 = $result; - $pos_298 = $this->pos; + $res_296 = $result; + $pos_296 = $this->pos; $key = "NotBlockTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $result = $res_298; - $this->pos = $pos_298; - $_310 = FALSE; break; + $result = $res_296; + $this->pos = $pos_296; + $_308 = FALSE; break; } else { - $result = $res_298; - $this->pos = $pos_298; + $result = $res_296; + $this->pos = $pos_296; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Tag" ); } - else { $_310 = FALSE; break; } - $res_309 = $result; - $pos_309 = $this->pos; - $_308 = NULL; + else { $_308 = FALSE; break; } + $res_307 = $result; + $pos_307 = $this->pos; + $_306 = NULL; do { - $res_304 = $result; - $pos_304 = $this->pos; - $_303 = NULL; + $res_302 = $result; + $pos_302 = $this->pos; + $_301 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_303 = FALSE; break; } + else { $_301 = FALSE; break; } $key = "BlockArguments"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockArguments" ); } - else { $_303 = FALSE; break; } + else { $_301 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_303 = FALSE; break; } - $_303 = TRUE; break; + else { $_301 = FALSE; break; } + $_301 = TRUE; break; } while(0); - if( $_303 === FALSE) { - $result = $res_304; - $this->pos = $pos_304; - unset( $res_304 ); - unset( $pos_304 ); + if( $_301 === FALSE) { + $result = $res_302; + $this->pos = $pos_302; + unset( $res_302 ); + unset( $pos_302 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_306 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_306->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_308 = FALSE; break; } - $_308 = TRUE; break; + $_304 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_304->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_306 = FALSE; break; } + $_306 = TRUE; break; } while(0); - if( $_308 === TRUE ) { - $result = $res_309; - $this->pos = $pos_309; - $_310 = FALSE; break; + if( $_306 === TRUE ) { + $result = $res_307; + $this->pos = $pos_307; + $_308 = FALSE; break; } - if( $_308 === FALSE) { - $result = $res_309; - $this->pos = $pos_309; + if( $_306 === FALSE) { + $result = $res_307; + $this->pos = $pos_307; } - $_310 = TRUE; break; + $_308 = TRUE; break; } while(0); - if( $_310 === TRUE ) { + if( $_308 === TRUE ) { return $this->finalise( "MalformedOpenTag", $result ); } - if( $_310 === FALSE) { return FALSE; } + if( $_308 === FALSE) { return FALSE; } } @@ -1776,64 +1753,64 @@ class SSTemplateParser extends Parser { /* MalformedCloseTag: '<%' < Tag:('end_' :Word ) !( > '%>' ) */ function match_MalformedCloseTag ($substack = array()) { $result = $this->construct( "MalformedCloseTag" ); - $_326 = NULL; + $_324 = NULL; do { - $_312 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_312->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_326 = FALSE; break; } + $_310 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_310->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_324 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $substack[] = $result; $result = $this->construct( "Tag" ); - $_318 = NULL; + $_316 = NULL; do { - $_315 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_315->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_318 = FALSE; break; } + $_313 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_313->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_316 = FALSE; break; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Word" ); } - else { $_318 = FALSE; break; } - $_318 = TRUE; break; + else { $_316 = FALSE; break; } + $_316 = TRUE; break; } while(0); - if( $_318 === TRUE ) { + if( $_316 === TRUE ) { $subres = $result ; $result = array_pop( $substack ) ; $this->store( $result, $subres, 'Tag' ); } - if( $_318 === FALSE) { + if( $_316 === FALSE) { $result = array_pop( $substack ) ; - $_326 = FALSE; break; + $_324 = FALSE; break; } - $res_325 = $result; - $pos_325 = $this->pos; - $_324 = NULL; + $res_323 = $result; + $pos_323 = $this->pos; + $_322 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_322 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_322->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_324 = FALSE; break; } - $_324 = TRUE; break; + $_320 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_320->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_322 = FALSE; break; } + $_322 = TRUE; break; } while(0); - if( $_324 === TRUE ) { - $result = $res_325; - $this->pos = $pos_325; - $_326 = FALSE; break; + if( $_322 === TRUE ) { + $result = $res_323; + $this->pos = $pos_323; + $_324 = FALSE; break; } - if( $_324 === FALSE) { - $result = $res_325; - $this->pos = $pos_325; + if( $_322 === FALSE) { + $result = $res_323; + $this->pos = $pos_323; } - $_326 = TRUE; break; + $_324 = TRUE; break; } while(0); - if( $_326 === TRUE ) { + if( $_324 === TRUE ) { return $this->finalise( "MalformedCloseTag", $result ); } - if( $_326 === FALSE) { return FALSE; } + if( $_324 === FALSE) { return FALSE; } } @@ -1846,33 +1823,33 @@ class SSTemplateParser extends Parser { /* MalformedBlock: MalformedOpenTag | MalformedCloseTag */ function match_MalformedBlock ($substack = array()) { $result = $this->construct( "MalformedBlock" ); - $_331 = NULL; + $_329 = NULL; do { - $res_328 = $result; - $pos_328 = $this->pos; + $res_326 = $result; + $pos_326 = $this->pos; $key = "MalformedOpenTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedOpenTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_331 = TRUE; break; + $_329 = TRUE; break; } - $result = $res_328; - $this->pos = $pos_328; + $result = $res_326; + $this->pos = $pos_326; $key = "MalformedCloseTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedCloseTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_331 = TRUE; break; + $_329 = TRUE; break; } - $result = $res_328; - $this->pos = $pos_328; - $_331 = FALSE; break; + $result = $res_326; + $this->pos = $pos_326; + $_329 = FALSE; break; } while(0); - if( $_331 === TRUE ) { + if( $_329 === TRUE ) { return $this->finalise( "MalformedBlock", $result ); } - if( $_331 === FALSE) { return FALSE; } + if( $_329 === FALSE) { return FALSE; } } @@ -1881,57 +1858,57 @@ class SSTemplateParser extends Parser { /* Comment: "<%--" (!"--%>" /./)+ "--%>" */ function match_Comment ($substack = array()) { $result = $this->construct( "Comment" ); - $_343 = NULL; + $_341 = NULL; do { - $_333 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_333->expand("<%--") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_343 = FALSE; break; } + $_331 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_331->expand("<%--") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_341 = FALSE; break; } $count = 0; while (true) { - $res_340 = $result; - $pos_340 = $this->pos; - $_339 = NULL; + $res_338 = $result; + $pos_338 = $this->pos; + $_337 = NULL; do { - $res_336 = $result; - $pos_336 = $this->pos; - $_335 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_335->expand("--%>") ) ) !== FALSE) { + $res_334 = $result; + $pos_334 = $this->pos; + $_333 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_333->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; - $result = $res_336; - $this->pos = $pos_336; - $_339 = FALSE; break; + $result = $res_334; + $this->pos = $pos_334; + $_337 = FALSE; break; } else { - $result = $res_336; - $this->pos = $pos_336; + $result = $res_334; + $this->pos = $pos_334; } - $_337 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_337->expand('/./') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_339 = FALSE; break; } - $_339 = TRUE; break; + $_335 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_335->expand('/./') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_337 = FALSE; break; } + $_337 = TRUE; break; } while(0); - if( $_339 === FALSE) { - $result = $res_340; - $this->pos = $pos_340; - unset( $res_340 ); - unset( $pos_340 ); + if( $_337 === FALSE) { + $result = $res_338; + $this->pos = $pos_338; + unset( $res_338 ); + unset( $pos_338 ); break; } $count += 1; } if ($count > 0) { } - else { $_343 = FALSE; break; } - $_341 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_341->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_343 = FALSE; break; } - $_343 = TRUE; break; + else { $_341 = FALSE; break; } + $_339 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_339->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_341 = FALSE; break; } + $_341 = TRUE; break; } while(0); - if( $_343 === TRUE ) { + if( $_341 === TRUE ) { return $this->finalise( "Comment", $result ); } - if( $_343 === FALSE) { return FALSE; } + if( $_341 === FALSE) { return FALSE; } } @@ -1952,8 +1929,8 @@ class SSTemplateParser extends Parser { / */ function match_Text ($substack = array()) { $result = array("name"=>"Text", "text"=>""); - $_345 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_345->expand('/ + $_343 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_343->expand('/ ( (\\\\.) | # Any escaped character ([^<${]) | # Any character that isn\'t <, $ or { @@ -1975,150 +1952,150 @@ class SSTemplateParser extends Parser { $result = $this->construct( "Template" ); $count = 0; while (true) { - $res_377 = $result; - $pos_377 = $this->pos; - $_376 = NULL; + $res_375 = $result; + $pos_375 = $this->pos; + $_374 = NULL; do { - $_374 = NULL; + $_372 = NULL; do { - $res_347 = $result; - $pos_347 = $this->pos; + $res_345 = $result; + $pos_345 = $this->pos; $key = "Comment"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comment(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_374 = TRUE; break; + $_372 = TRUE; break; } - $result = $res_347; - $this->pos = $pos_347; - $_372 = NULL; + $result = $res_345; + $this->pos = $pos_345; + $_370 = NULL; do { - $res_349 = $result; - $pos_349 = $this->pos; + $res_347 = $result; + $pos_347 = $this->pos; $key = "If"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_If(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_372 = TRUE; break; + $_370 = TRUE; break; } - $result = $res_349; - $this->pos = $pos_349; - $_370 = NULL; + $result = $res_347; + $this->pos = $pos_347; + $_368 = NULL; do { - $res_351 = $result; - $pos_351 = $this->pos; + $res_349 = $result; + $pos_349 = $this->pos; $key = "Require"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Require(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_370 = TRUE; break; + $_368 = TRUE; break; } - $result = $res_351; - $this->pos = $pos_351; - $_368 = NULL; + $result = $res_349; + $this->pos = $pos_349; + $_366 = NULL; do { - $res_353 = $result; - $pos_353 = $this->pos; + $res_351 = $result; + $pos_351 = $this->pos; $key = "ClosedBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_368 = TRUE; break; + $_366 = TRUE; break; } - $result = $res_353; - $this->pos = $pos_353; - $_366 = NULL; + $result = $res_351; + $this->pos = $pos_351; + $_364 = NULL; do { - $res_355 = $result; - $pos_355 = $this->pos; + $res_353 = $result; + $pos_353 = $this->pos; $key = "OpenBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_366 = TRUE; break; + $_364 = TRUE; break; } - $result = $res_355; - $this->pos = $pos_355; - $_364 = NULL; + $result = $res_353; + $this->pos = $pos_353; + $_362 = NULL; do { - $res_357 = $result; - $pos_357 = $this->pos; + $res_355 = $result; + $pos_355 = $this->pos; $key = "MalformedBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_364 = TRUE; break; + $_362 = TRUE; break; } - $result = $res_357; - $this->pos = $pos_357; - $_362 = NULL; + $result = $res_355; + $this->pos = $pos_355; + $_360 = NULL; do { - $res_359 = $result; - $pos_359 = $this->pos; + $res_357 = $result; + $pos_357 = $this->pos; $key = "Injection"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_362 = TRUE; break; + $_360 = TRUE; break; } - $result = $res_359; - $this->pos = $pos_359; + $result = $res_357; + $this->pos = $pos_357; $key = "Text"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_362 = TRUE; break; + $_360 = TRUE; break; } - $result = $res_359; - $this->pos = $pos_359; - $_362 = FALSE; break; + $result = $res_357; + $this->pos = $pos_357; + $_360 = FALSE; break; } while(0); - if( $_362 === TRUE ) { $_364 = TRUE; break; } - $result = $res_357; - $this->pos = $pos_357; - $_364 = FALSE; break; + if( $_360 === TRUE ) { $_362 = TRUE; break; } + $result = $res_355; + $this->pos = $pos_355; + $_362 = FALSE; break; } while(0); - if( $_364 === TRUE ) { $_366 = TRUE; break; } - $result = $res_355; - $this->pos = $pos_355; - $_366 = FALSE; break; + if( $_362 === TRUE ) { $_364 = TRUE; break; } + $result = $res_353; + $this->pos = $pos_353; + $_364 = FALSE; break; } while(0); - if( $_366 === TRUE ) { $_368 = TRUE; break; } - $result = $res_353; - $this->pos = $pos_353; - $_368 = FALSE; break; + if( $_364 === TRUE ) { $_366 = TRUE; break; } + $result = $res_351; + $this->pos = $pos_351; + $_366 = FALSE; break; } while(0); - if( $_368 === TRUE ) { $_370 = TRUE; break; } - $result = $res_351; - $this->pos = $pos_351; - $_370 = FALSE; break; + if( $_366 === TRUE ) { $_368 = TRUE; break; } + $result = $res_349; + $this->pos = $pos_349; + $_368 = FALSE; break; } while(0); - if( $_370 === TRUE ) { $_372 = TRUE; break; } - $result = $res_349; - $this->pos = $pos_349; - $_372 = FALSE; break; + if( $_368 === TRUE ) { $_370 = TRUE; break; } + $result = $res_347; + $this->pos = $pos_347; + $_370 = FALSE; break; } while(0); - if( $_372 === TRUE ) { $_374 = TRUE; break; } - $result = $res_347; - $this->pos = $pos_347; - $_374 = FALSE; break; + if( $_370 === TRUE ) { $_372 = TRUE; break; } + $result = $res_345; + $this->pos = $pos_345; + $_372 = FALSE; break; } while(0); - if( $_374 === FALSE) { $_376 = FALSE; break; } - $_376 = TRUE; break; + if( $_372 === FALSE) { $_374 = FALSE; break; } + $_374 = TRUE; break; } while(0); - if( $_376 === FALSE) { - $result = $res_377; - $this->pos = $pos_377; - unset( $res_377 ); - unset( $pos_377 ); + if( $_374 === FALSE) { + $result = $res_375; + $this->pos = $pos_375; + unset( $res_375 ); + unset( $pos_375 ); break; } $count += 1; @@ -2161,168 +2138,168 @@ class SSTemplateParser extends Parser { $result = $this->construct( "TopTemplate" ); $count = 0; while (true) { - $res_412 = $result; - $pos_412 = $this->pos; - $_411 = NULL; + $res_410 = $result; + $pos_410 = $this->pos; + $_409 = NULL; do { - $_409 = NULL; + $_407 = NULL; do { - $res_378 = $result; - $pos_378 = $this->pos; + $res_376 = $result; + $pos_376 = $this->pos; $key = "Comment"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comment(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_409 = TRUE; break; + $_407 = TRUE; break; } - $result = $res_378; - $this->pos = $pos_378; - $_407 = NULL; + $result = $res_376; + $this->pos = $pos_376; + $_405 = NULL; do { - $res_380 = $result; - $pos_380 = $this->pos; + $res_378 = $result; + $pos_378 = $this->pos; $key = "If"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_If(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_407 = TRUE; break; + $_405 = TRUE; break; } - $result = $res_380; - $this->pos = $pos_380; - $_405 = NULL; + $result = $res_378; + $this->pos = $pos_378; + $_403 = NULL; do { - $res_382 = $result; - $pos_382 = $this->pos; + $res_380 = $result; + $pos_380 = $this->pos; $key = "Require"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Require(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_405 = TRUE; break; + $_403 = TRUE; break; } - $result = $res_382; - $this->pos = $pos_382; - $_403 = NULL; + $result = $res_380; + $this->pos = $pos_380; + $_401 = NULL; do { - $res_384 = $result; - $pos_384 = $this->pos; + $res_382 = $result; + $pos_382 = $this->pos; $key = "ClosedBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_403 = TRUE; break; + $_401 = TRUE; break; } - $result = $res_384; - $this->pos = $pos_384; - $_401 = NULL; + $result = $res_382; + $this->pos = $pos_382; + $_399 = NULL; do { - $res_386 = $result; - $pos_386 = $this->pos; + $res_384 = $result; + $pos_384 = $this->pos; $key = "OpenBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_401 = TRUE; break; + $_399 = TRUE; break; } - $result = $res_386; - $this->pos = $pos_386; - $_399 = NULL; + $result = $res_384; + $this->pos = $pos_384; + $_397 = NULL; do { - $res_388 = $result; - $pos_388 = $this->pos; + $res_386 = $result; + $pos_386 = $this->pos; $key = "MalformedBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_399 = TRUE; break; + $_397 = TRUE; break; } - $result = $res_388; - $this->pos = $pos_388; - $_397 = NULL; + $result = $res_386; + $this->pos = $pos_386; + $_395 = NULL; do { - $res_390 = $result; - $pos_390 = $this->pos; + $res_388 = $result; + $pos_388 = $this->pos; $key = "MismatchedEndBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MismatchedEndBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_397 = TRUE; break; + $_395 = TRUE; break; } - $result = $res_390; - $this->pos = $pos_390; - $_395 = NULL; + $result = $res_388; + $this->pos = $pos_388; + $_393 = NULL; do { - $res_392 = $result; - $pos_392 = $this->pos; + $res_390 = $result; + $pos_390 = $this->pos; $key = "Injection"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_395 = TRUE; break; + $_393 = TRUE; break; } - $result = $res_392; - $this->pos = $pos_392; + $result = $res_390; + $this->pos = $pos_390; $key = "Text"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_395 = TRUE; break; + $_393 = TRUE; break; } - $result = $res_392; - $this->pos = $pos_392; - $_395 = FALSE; break; + $result = $res_390; + $this->pos = $pos_390; + $_393 = FALSE; break; } while(0); - if( $_395 === TRUE ) { $_397 = TRUE; break; } - $result = $res_390; - $this->pos = $pos_390; - $_397 = FALSE; break; + if( $_393 === TRUE ) { $_395 = TRUE; break; } + $result = $res_388; + $this->pos = $pos_388; + $_395 = FALSE; break; } while(0); - if( $_397 === TRUE ) { $_399 = TRUE; break; } - $result = $res_388; - $this->pos = $pos_388; - $_399 = FALSE; break; + if( $_395 === TRUE ) { $_397 = TRUE; break; } + $result = $res_386; + $this->pos = $pos_386; + $_397 = FALSE; break; } while(0); - if( $_399 === TRUE ) { $_401 = TRUE; break; } - $result = $res_386; - $this->pos = $pos_386; - $_401 = FALSE; break; + if( $_397 === TRUE ) { $_399 = TRUE; break; } + $result = $res_384; + $this->pos = $pos_384; + $_399 = FALSE; break; } while(0); - if( $_401 === TRUE ) { $_403 = TRUE; break; } - $result = $res_384; - $this->pos = $pos_384; - $_403 = FALSE; break; + if( $_399 === TRUE ) { $_401 = TRUE; break; } + $result = $res_382; + $this->pos = $pos_382; + $_401 = FALSE; break; } while(0); - if( $_403 === TRUE ) { $_405 = TRUE; break; } - $result = $res_382; - $this->pos = $pos_382; - $_405 = FALSE; break; + if( $_401 === TRUE ) { $_403 = TRUE; break; } + $result = $res_380; + $this->pos = $pos_380; + $_403 = FALSE; break; } while(0); - if( $_405 === TRUE ) { $_407 = TRUE; break; } - $result = $res_380; - $this->pos = $pos_380; - $_407 = FALSE; break; + if( $_403 === TRUE ) { $_405 = TRUE; break; } + $result = $res_378; + $this->pos = $pos_378; + $_405 = FALSE; break; } while(0); - if( $_407 === TRUE ) { $_409 = TRUE; break; } - $result = $res_378; - $this->pos = $pos_378; - $_409 = FALSE; break; + if( $_405 === TRUE ) { $_407 = TRUE; break; } + $result = $res_376; + $this->pos = $pos_376; + $_407 = FALSE; break; } while(0); - if( $_409 === FALSE) { $_411 = FALSE; break; } - $_411 = TRUE; break; + if( $_407 === FALSE) { $_409 = FALSE; break; } + $_409 = TRUE; break; } while(0); - if( $_411 === FALSE) { - $result = $res_412; - $this->pos = $pos_412; - unset( $res_412 ); - unset( $pos_412 ); + if( $_409 === FALSE) { + $result = $res_410; + $this->pos = $pos_410; + unset( $res_410 ); + unset( $pos_410 ); break; } $count += 1; diff --git a/core/SSTemplateParser.php.inc b/core/SSTemplateParser.php.inc index 7fd229833..da882fcac 100644 --- a/core/SSTemplateParser.php.inc +++ b/core/SSTemplateParser.php.inc @@ -61,10 +61,6 @@ class SSTemplateParser extends Parser { return $result; } - function DLRBlockName() { - return '-none-'; - } - /*!* SSTemplateParser Word: / [A-Za-z_] [A-Za-z0-9_]* / @@ -236,10 +232,6 @@ class SSTemplateParser extends Parser { If: IfPart ElseIfPart* ElsePart? '<%' < 'end_if' > '%>' */ - function If__construct(&$res) { - $res['BlockName'] = 'if'; - } - function If_IfPart(&$res, $sub) { $res['php'] = 'if (' . $sub['IfArgument']['php'] . ') { ' . PHP_EOL . @@ -318,7 +310,7 @@ class SSTemplateParser extends Parser { } /*!* - OpenBlock: '<%' < !NotBlockTag OpenBlockName:Word ( [ :BlockArguments ] )? > '%>' + OpenBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > '%>' */ function OpenBlock__construct(&$res) { $res['ArgumentCount'] = 0; @@ -336,7 +328,7 @@ class SSTemplateParser extends Parser { } function OpenBlock__finalise(&$res) { - $blockname = $res['OpenBlockName']['text']; + $blockname = $res['BlockName']['text']; $method = 'OpenBlock_Handle_'.ucfirst(strtolower($blockname)); if (method_exists($this, $method)) $res['php'] = $this->$method($res); @@ -389,7 +381,7 @@ class SSTemplateParser extends Parser { } /*!* - MismatchedEndBlock: '<%' < 'end_' !'$BlockName' :Word > '%>' + MismatchedEndBlock: '<%' < 'end_' Word > '%>' */ function MismatchedEndBlock__finalise(&$res) { $blockname = $res['Word']['text']; From 829bf2319262b3055da110e21fdcbc2ba7e103b5 Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Tue, 15 Feb 2011 10:03:42 +1300 Subject: [PATCH 06/15] MINOR: Add inline documentation to SSTemplateParser --- core/SSTemplateParser.php | 1581 +++++++++++++++++---------------- core/SSTemplateParser.php.inc | 240 ++++- 2 files changed, 1066 insertions(+), 755 deletions(-) diff --git a/core/SSTemplateParser.php b/core/SSTemplateParser.php index dd3c2e9c7..3e9b7a0d3 100644 --- a/core/SSTemplateParser.php +++ b/core/SSTemplateParser.php @@ -36,9 +36,35 @@ class SSTemplateParseException extends Exception { /** This is the parser for the SilverStripe template language. It gets called on a string and uses a php-peg parser to match that string against the language structure, building up the PHP code to execute that structure as it parses + +The $result array that is built up as part of the parsing (see thirdparty/php-peg/README.md for more on how parsers +build results) has one special member, 'php', which contains the php equivalent of that part of the template tree. + +Some match rules generate alternate php, or other variations, so check the per-match documentation too. + +Terms used: + +Marked: A string or lookup in the template that has been explictly marked as such - lookups by prepending with "$" +(like $Foo.Bar), strings by wrapping with single or double quotes ('Foo' or "Foo") + +Bare: The opposite of marked. An argument that has to has it's type inferred by usage and 2.4 defaults. +Example of using a bare argument for a loop block: <% loop Foo %> + +Block: One of two SS template structures. The special characters "<%" and "%>" are used to wrap the opening and +(required or forbidden depending on which block exactly) closing block marks. + +Open Block: An SS template block that doesn't wrap any content or have a closing end tag (in fact, a closing end tag is +forbidden) + +Closed Block: An SS template block that wraps content, and requires a counterpart <% end_blockname %> tag + */ class SSTemplateParser extends Parser { + /** + * @var bool - Set true by SSTemplateParser::compileString if the template should include comments intended + * for debugging (template source, included files, etc) + */ protected $includeDebuggingComments = false; function construct($name) { @@ -83,9 +109,9 @@ class SSTemplateParser extends Parser { } - /* Arguments: :Argument ( < "," < :Argument )* */ - function match_Arguments ($substack = array()) { - $result = $this->construct( "Arguments" ); + /* CallArguments: :Argument ( < "," < :Argument )* */ + function match_CallArguments ($substack = array()) { + $result = $this->construct( "CallArguments" ); $_13 = NULL; do { $key = "Argument"; $pos = $this->pos; @@ -127,7 +153,7 @@ class SSTemplateParser extends Parser { } while(0); if( $_13 === TRUE ) { - return $this->finalise( "Arguments", $result ); + return $this->finalise( "CallArguments", $result ); } if( $_13 === FALSE) { return FALSE; } } @@ -135,15 +161,18 @@ class SSTemplateParser extends Parser { - /** Values are bare words in templates, but strings in PHP. We rely on PHP's type conversion to back-convert strings to numbers when needed */ - function Arguments_Argument(&$res, $sub) { + /** + * Values are bare words in templates, but strings in PHP. We rely on PHP's type conversion to back-convert strings + * to numbers when needed. + */ + function CallArguments_Argument(&$res, $sub) { if (isset($res['php'])) $res['php'] .= ', '; else $res['php'] = ''; $res['php'] .= ($sub['ArgumentMode'] == 'default') ? $sub['string_php'] : $sub['php']; } - /* Call: Method:Word ( "(" < :Arguments? > ")" )? */ + /* Call: Method:Word ( "(" < :CallArguments? > ")" )? */ function match_Call ($substack = array()) { $result = $this->construct( "Call" ); $_23 = NULL; @@ -166,10 +195,10 @@ class SSTemplateParser extends Parser { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $res_18 = $result; $pos_18 = $this->pos; - $key = "Arguments"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Arguments(array_merge($substack, array($result))) ) ); + $key = "CallArguments"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_CallArguments(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { - $this->store( $result, $subres, "Arguments" ); + $this->store( $result, $subres, "CallArguments" ); } else { $result = $res_18; @@ -329,12 +358,17 @@ class SSTemplateParser extends Parser { $res['LookupSteps'] = array(); } + /** + * The basic generated PHP of LookupStep and LastLookupStep is the same, except that LookupStep calls 'obj' to + * get the next ViewableData in the sequence, and LastLookupStep calls different methods (XML_val, hasValue, obj) + * depending on the context the lookup is used in. + */ function Lookup_AddLookupStep(&$res, $sub, $method) { $res['LookupSteps'][] = $sub; $property = $sub['Call']['Method']['text']; - if (isset($sub['Call']['Arguments']) && $arguments = $sub['Call']['Arguments']['php']) { + if (isset($sub['Call']['CallArguments']) && $arguments = $sub['Call']['CallArguments']['php']) { $res['php'] .= "->$method('$property', array($arguments), true)"; } else { @@ -443,36 +477,16 @@ class SSTemplateParser extends Parser { $res['php'] = '$val .= '. $sub['Lookup']['php'] . ';'; } - /* DollarMarkedLookup: BracketInjection | SimpleInjection */ + /* DollarMarkedLookup: SimpleInjection */ function match_DollarMarkedLookup ($substack = array()) { $result = $this->construct( "DollarMarkedLookup" ); - $_61 = NULL; - do { - $res_58 = $result; - $pos_58 = $this->pos; - $key = "BracketInjection"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BracketInjection(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_61 = TRUE; break; - } - $result = $res_58; - $this->pos = $pos_58; - $key = "SimpleInjection"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_SimpleInjection(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_61 = TRUE; break; - } - $result = $res_58; - $this->pos = $pos_58; - $_61 = FALSE; break; - } - while(0); - if( $_61 === TRUE ) { + $key = "SimpleInjection"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_SimpleInjection(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); return $this->finalise( "DollarMarkedLookup", $result ); } - if( $_61 === FALSE) { return FALSE; } + else { return FALSE; } } @@ -484,12 +498,12 @@ class SSTemplateParser extends Parser { /* QuotedString: q:/['"]/ String:/ (\\\\ | \\. | [^$q\\])* / '$q' */ function match_QuotedString ($substack = array()) { $result = $this->construct( "QuotedString" ); - $_71 = NULL; + $_67 = NULL; do { $substack[] = $result; $result = $this->construct( "q" ); - $_63 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_63->expand('/[\'"]/') ) ) !== FALSE) { + $_59 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_59->expand('/[\'"]/') ) ) !== FALSE) { $result["text"] .= $subres; $subres = $result ; $result = array_pop( $substack ) ; @@ -497,12 +511,12 @@ class SSTemplateParser extends Parser { } else { $result = array_pop( $substack ) ; - $_71 = FALSE; break; + $_67 = FALSE; break; } $substack[] = $result; $result = $this->construct( "String" ); - $_66 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_66->expand('/ (\\\\\\\\ | \\\\. | [^$q\\\\])* /') ) ) !== FALSE) { + $_62 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_62->expand('/ (\\\\\\\\ | \\\\. | [^$q\\\\])* /') ) ) !== FALSE) { $result["text"] .= $subres; $subres = $result ; $result = array_pop( $substack ) ; @@ -510,26 +524,26 @@ class SSTemplateParser extends Parser { } else { $result = array_pop( $substack ) ; - $_71 = FALSE; break; + $_67 = FALSE; break; } - $_69 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_69->expand('$q') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_71 = FALSE; break; } - $_71 = TRUE; break; + $_65 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_65->expand('$q') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_67 = FALSE; break; } + $_67 = TRUE; break; } while(0); - if( $_71 === TRUE ) { + if( $_67 === TRUE ) { return $this->finalise( "QuotedString", $result ); } - if( $_71 === FALSE) { return FALSE; } + if( $_67 === FALSE) { return FALSE; } } /* FreeString: /[^,)%!=|&]+/ */ function match_FreeString ($substack = array()) { $result = array("name"=>"FreeString", "text"=>""); - $_73 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_73->expand('/[^,)%!=|&]+/') ) ) !== FALSE) { + $_69 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_69->expand('/[^,)%!=|&]+/') ) ) !== FALSE) { $result["text"] .= $subres; return $result; } @@ -544,45 +558,45 @@ class SSTemplateParser extends Parser { :FreeString */ function match_Argument ($substack = array()) { $result = $this->construct( "Argument" ); - $_92 = NULL; + $_88 = NULL; do { - $res_75 = $result; - $pos_75 = $this->pos; + $res_71 = $result; + $pos_71 = $this->pos; $key = "DollarMarkedLookup"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_DollarMarkedLookup(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "DollarMarkedLookup" ); - $_92 = TRUE; break; + $_88 = TRUE; break; } - $result = $res_75; - $this->pos = $pos_75; - $_90 = NULL; + $result = $res_71; + $this->pos = $pos_71; + $_86 = NULL; do { - $res_77 = $result; - $pos_77 = $this->pos; + $res_73 = $result; + $pos_73 = $this->pos; $key = "QuotedString"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_QuotedString(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "QuotedString" ); - $_90 = TRUE; break; + $_86 = TRUE; break; } - $result = $res_77; - $this->pos = $pos_77; - $_88 = NULL; + $result = $res_73; + $this->pos = $pos_73; + $_84 = NULL; do { - $res_79 = $result; - $pos_79 = $this->pos; - $_85 = NULL; + $res_75 = $result; + $pos_75 = $this->pos; + $_81 = NULL; do { $key = "Lookup"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Lookup(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Lookup" ); } - else { $_85 = FALSE; break; } - $res_84 = $result; - $pos_84 = $this->pos; - $_83 = NULL; + else { $_81 = FALSE; break; } + $res_80 = $result; + $pos_80 = $this->pos; + $_79 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $key = "FreeString"; $pos = $this->pos; @@ -590,56 +604,71 @@ class SSTemplateParser extends Parser { if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_83 = FALSE; break; } - $_83 = TRUE; break; + else { $_79 = FALSE; break; } + $_79 = TRUE; break; } while(0); - if( $_83 === TRUE ) { - $result = $res_84; - $this->pos = $pos_84; - $_85 = FALSE; break; + if( $_79 === TRUE ) { + $result = $res_80; + $this->pos = $pos_80; + $_81 = FALSE; break; } - if( $_83 === FALSE) { - $result = $res_84; - $this->pos = $pos_84; + if( $_79 === FALSE) { + $result = $res_80; + $this->pos = $pos_80; } - $_85 = TRUE; break; + $_81 = TRUE; break; } while(0); - if( $_85 === TRUE ) { $_88 = TRUE; break; } - $result = $res_79; - $this->pos = $pos_79; + if( $_81 === TRUE ) { $_84 = TRUE; break; } + $result = $res_75; + $this->pos = $pos_75; $key = "FreeString"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_FreeString(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "FreeString" ); - $_88 = TRUE; break; + $_84 = TRUE; break; } - $result = $res_79; - $this->pos = $pos_79; - $_88 = FALSE; break; + $result = $res_75; + $this->pos = $pos_75; + $_84 = FALSE; break; } while(0); - if( $_88 === TRUE ) { $_90 = TRUE; break; } - $result = $res_77; - $this->pos = $pos_77; - $_90 = FALSE; break; + if( $_84 === TRUE ) { $_86 = TRUE; break; } + $result = $res_73; + $this->pos = $pos_73; + $_86 = FALSE; break; } while(0); - if( $_90 === TRUE ) { $_92 = TRUE; break; } - $result = $res_75; - $this->pos = $pos_75; - $_92 = FALSE; break; + if( $_86 === TRUE ) { $_88 = TRUE; break; } + $result = $res_71; + $this->pos = $pos_71; + $_88 = FALSE; break; } while(0); - if( $_92 === TRUE ) { + if( $_88 === TRUE ) { return $this->finalise( "Argument", $result ); } - if( $_92 === FALSE) { return FALSE; } + if( $_88 === FALSE) { return FALSE; } } + + /** + * If we get a bare value, we don't know enough to determine exactly what php would be the translation, because + * we don't know if the position of use indicates a lookup or a string argument. + * + * Instead, we record 'ArgumentMode' as a member of this matches results node, which can be: + * - lookup if this argument was unambiguously a lookup (marked as such) + * - string is this argument was unambiguously a string (marked as such, or impossible to parse as lookup) + * - default if this argument needs to be handled as per 2.4 + * + * In the case of 'default', there is no php member of the results node, but instead 'lookup_php', which + * should be used by the parent if the context indicates a lookup, and 'string_php' which should be used + * if the context indicates a string + */ + function Argument_DollarMarkedLookup(&$res, $sub) { $res['ArgumentMode'] = 'lookup'; $res['php'] = $sub['Lookup']['php']; @@ -670,77 +699,77 @@ class SSTemplateParser extends Parser { /* ComparisonOperator: "==" | "!=" | "=" */ function match_ComparisonOperator ($substack = array()) { $result = $this->construct( "ComparisonOperator" ); - $_103 = NULL; + $_99 = NULL; do { - $res_94 = $result; - $pos_94 = $this->pos; - $_95 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_95->expand("==") ) ) !== FALSE) { + $res_90 = $result; + $pos_90 = $this->pos; + $_91 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_91->expand("==") ) ) !== FALSE) { $result["text"] .= $subres; - $_103 = TRUE; break; + $_99 = TRUE; break; } - $result = $res_94; - $this->pos = $pos_94; - $_101 = NULL; + $result = $res_90; + $this->pos = $pos_90; + $_97 = NULL; do { - $res_97 = $result; - $pos_97 = $this->pos; - $_98 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_98->expand("!=") ) ) !== FALSE) { + $res_93 = $result; + $pos_93 = $this->pos; + $_94 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_94->expand("!=") ) ) !== FALSE) { $result["text"] .= $subres; - $_101 = TRUE; break; + $_97 = TRUE; break; } - $result = $res_97; - $this->pos = $pos_97; + $result = $res_93; + $this->pos = $pos_93; if (substr($this->string,$this->pos,1) == "=") { $this->pos += 1; $result["text"] .= "="; - $_101 = TRUE; break; + $_97 = TRUE; break; } - $result = $res_97; - $this->pos = $pos_97; - $_101 = FALSE; break; + $result = $res_93; + $this->pos = $pos_93; + $_97 = FALSE; break; } while(0); - if( $_101 === TRUE ) { $_103 = TRUE; break; } - $result = $res_94; - $this->pos = $pos_94; - $_103 = FALSE; break; + if( $_97 === TRUE ) { $_99 = TRUE; break; } + $result = $res_90; + $this->pos = $pos_90; + $_99 = FALSE; break; } while(0); - if( $_103 === TRUE ) { + if( $_99 === TRUE ) { return $this->finalise( "ComparisonOperator", $result ); } - if( $_103 === FALSE) { return FALSE; } + if( $_99 === FALSE) { return FALSE; } } /* Comparison: Argument < ComparisonOperator > Argument */ function match_Comparison ($substack = array()) { $result = $this->construct( "Comparison" ); - $_110 = NULL; + $_106 = NULL; do { $key = "Argument"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_110 = FALSE; break; } + else { $_106 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $key = "ComparisonOperator"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ComparisonOperator(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_110 = FALSE; break; } + else { $_106 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $key = "Argument"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_110 = FALSE; break; } - $_110 = TRUE; break; + else { $_106 = FALSE; break; } + $_106 = TRUE; break; } while(0); - if( $_110 === TRUE ) { + if( $_106 === TRUE ) { return $this->finalise( "Comparison", $result ); } - if( $_110 === FALSE) { return FALSE; } + if( $_106 === FALSE) { return FALSE; } } @@ -789,33 +818,33 @@ class SSTemplateParser extends Parser { /* IfArgumentPortion: Comparison | PresenceCheck */ function match_IfArgumentPortion ($substack = array()) { $result = $this->construct( "IfArgumentPortion" ); - $_116 = NULL; + $_112 = NULL; do { - $res_113 = $result; - $pos_113 = $this->pos; + $res_109 = $result; + $pos_109 = $this->pos; $key = "Comparison"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comparison(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_116 = TRUE; break; + $_112 = TRUE; break; } - $result = $res_113; - $this->pos = $pos_113; + $result = $res_109; + $this->pos = $pos_109; $key = "PresenceCheck"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_PresenceCheck(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_116 = TRUE; break; + $_112 = TRUE; break; } - $result = $res_113; - $this->pos = $pos_113; - $_116 = FALSE; break; + $result = $res_109; + $this->pos = $pos_109; + $_112 = FALSE; break; } while(0); - if( $_116 === TRUE ) { + if( $_112 === TRUE ) { return $this->finalise( "IfArgumentPortion", $result ); } - if( $_116 === FALSE) { return FALSE; } + if( $_112 === FALSE) { return FALSE; } } @@ -827,49 +856,49 @@ class SSTemplateParser extends Parser { /* BooleanOperator: "||" | "&&" */ function match_BooleanOperator ($substack = array()) { $result = $this->construct( "BooleanOperator" ); - $_123 = NULL; + $_119 = NULL; do { - $res_118 = $result; - $pos_118 = $this->pos; - $_119 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_119->expand("||") ) ) !== FALSE) { + $res_114 = $result; + $pos_114 = $this->pos; + $_115 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_115->expand("||") ) ) !== FALSE) { $result["text"] .= $subres; - $_123 = TRUE; break; + $_119 = TRUE; break; } - $result = $res_118; - $this->pos = $pos_118; - $_121 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_121->expand("&&") ) ) !== FALSE) { + $result = $res_114; + $this->pos = $pos_114; + $_117 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_117->expand("&&") ) ) !== FALSE) { $result["text"] .= $subres; - $_123 = TRUE; break; + $_119 = TRUE; break; } - $result = $res_118; - $this->pos = $pos_118; - $_123 = FALSE; break; + $result = $res_114; + $this->pos = $pos_114; + $_119 = FALSE; break; } while(0); - if( $_123 === TRUE ) { + if( $_119 === TRUE ) { return $this->finalise( "BooleanOperator", $result ); } - if( $_123 === FALSE) { return FALSE; } + if( $_119 === FALSE) { return FALSE; } } /* IfArgument: :IfArgumentPortion ( < :BooleanOperator < :IfArgumentPortion )* */ function match_IfArgument ($substack = array()) { $result = $this->construct( "IfArgument" ); - $_132 = NULL; + $_128 = NULL; do { $key = "IfArgumentPortion"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgumentPortion(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "IfArgumentPortion" ); } - else { $_132 = FALSE; break; } + else { $_128 = FALSE; break; } while (true) { - $res_131 = $result; - $pos_131 = $this->pos; - $_130 = NULL; + $res_127 = $result; + $pos_127 = $this->pos; + $_126 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $key = "BooleanOperator"; $pos = $this->pos; @@ -877,32 +906,32 @@ class SSTemplateParser extends Parser { if ($subres !== FALSE) { $this->store( $result, $subres, "BooleanOperator" ); } - else { $_130 = FALSE; break; } + else { $_126 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $key = "IfArgumentPortion"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgumentPortion(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "IfArgumentPortion" ); } - else { $_130 = FALSE; break; } - $_130 = TRUE; break; + else { $_126 = FALSE; break; } + $_126 = TRUE; break; } while(0); - if( $_130 === FALSE) { - $result = $res_131; - $this->pos = $pos_131; - unset( $res_131 ); - unset( $pos_131 ); + if( $_126 === FALSE) { + $result = $res_127; + $this->pos = $pos_127; + unset( $res_127 ); + unset( $pos_127 ); break; } } - $_132 = TRUE; break; + $_128 = TRUE; break; } while(0); - if( $_132 === TRUE ) { + if( $_128 === TRUE ) { return $this->finalise( "IfArgument", $result ); } - if( $_132 === FALSE) { return FALSE; } + if( $_128 === FALSE) { return FALSE; } } @@ -921,186 +950,186 @@ class SSTemplateParser extends Parser { /* IfPart: '<%' < 'if' < :IfArgument > '%>' :Template? */ function match_IfPart ($substack = array()) { $result = $this->construct( "IfPart" ); - $_145 = NULL; + $_141 = NULL; do { - $_134 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_134->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_145 = FALSE; break; } + $_130 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_130->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_141 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_137 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_137->expand('if') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_145 = FALSE; break; } + $_133 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_133->expand('if') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_141 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $key = "IfArgument"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgument(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "IfArgument" ); } - else { $_145 = FALSE; break; } + else { $_141 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_142 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_142->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_145 = FALSE; break; } - $res_144 = $result; - $pos_144 = $this->pos; + $_138 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_138->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_141 = FALSE; break; } + $res_140 = $result; + $pos_140 = $this->pos; $key = "Template"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Template" ); } else { - $result = $res_144; - $this->pos = $pos_144; - unset( $res_144 ); - unset( $pos_144 ); + $result = $res_140; + $this->pos = $pos_140; + unset( $res_140 ); + unset( $pos_140 ); } - $_145 = TRUE; break; + $_141 = TRUE; break; } while(0); - if( $_145 === TRUE ) { + if( $_141 === TRUE ) { return $this->finalise( "IfPart", $result ); } - if( $_145 === FALSE) { return FALSE; } + if( $_141 === FALSE) { return FALSE; } } /* ElseIfPart: '<%' < 'else_if' < :IfArgument > '%>' :Template? */ function match_ElseIfPart ($substack = array()) { $result = $this->construct( "ElseIfPart" ); - $_158 = NULL; + $_154 = NULL; do { - $_147 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_147->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_158 = FALSE; break; } + $_143 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_143->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_154 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_150 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_150->expand('else_if') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_158 = FALSE; break; } + $_146 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_146->expand('else_if') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_154 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $key = "IfArgument"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgument(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "IfArgument" ); } - else { $_158 = FALSE; break; } + else { $_154 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_155 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_155->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_158 = FALSE; break; } - $res_157 = $result; - $pos_157 = $this->pos; + $_151 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_151->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_154 = FALSE; break; } + $res_153 = $result; + $pos_153 = $this->pos; $key = "Template"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Template" ); } else { - $result = $res_157; - $this->pos = $pos_157; - unset( $res_157 ); - unset( $pos_157 ); + $result = $res_153; + $this->pos = $pos_153; + unset( $res_153 ); + unset( $pos_153 ); } - $_158 = TRUE; break; + $_154 = TRUE; break; } while(0); - if( $_158 === TRUE ) { + if( $_154 === TRUE ) { return $this->finalise( "ElseIfPart", $result ); } - if( $_158 === FALSE) { return FALSE; } + if( $_154 === FALSE) { return FALSE; } } /* ElsePart: '<%' < 'else' > '%>' :Template? */ function match_ElsePart ($substack = array()) { $result = $this->construct( "ElsePart" ); - $_169 = NULL; + $_165 = NULL; do { - $_160 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_160->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_169 = FALSE; break; } + $_156 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_156->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_165 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_163 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_163->expand('else') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_169 = FALSE; break; } + $_159 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_159->expand('else') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_165 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_166 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_166->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_169 = FALSE; break; } - $res_168 = $result; - $pos_168 = $this->pos; + $_162 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_162->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_165 = FALSE; break; } + $res_164 = $result; + $pos_164 = $this->pos; $key = "Template"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Template" ); } else { - $result = $res_168; - $this->pos = $pos_168; - unset( $res_168 ); - unset( $pos_168 ); + $result = $res_164; + $this->pos = $pos_164; + unset( $res_164 ); + unset( $pos_164 ); } - $_169 = TRUE; break; + $_165 = TRUE; break; } while(0); - if( $_169 === TRUE ) { + if( $_165 === TRUE ) { return $this->finalise( "ElsePart", $result ); } - if( $_169 === FALSE) { return FALSE; } + if( $_165 === FALSE) { return FALSE; } } /* If: IfPart ElseIfPart* ElsePart? '<%' < 'end_if' > '%>' */ function match_If ($substack = array()) { $result = $this->construct( "If" ); - $_182 = NULL; + $_178 = NULL; do { $key = "IfPart"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfPart(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_182 = FALSE; break; } + else { $_178 = FALSE; break; } while (true) { - $res_172 = $result; - $pos_172 = $this->pos; + $res_168 = $result; + $pos_168 = $this->pos; $key = "ElseIfPart"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ElseIfPart(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } else { - $result = $res_172; - $this->pos = $pos_172; - unset( $res_172 ); - unset( $pos_172 ); + $result = $res_168; + $this->pos = $pos_168; + unset( $res_168 ); + unset( $pos_168 ); break; } } - $res_173 = $result; - $pos_173 = $this->pos; + $res_169 = $result; + $pos_169 = $this->pos; $key = "ElsePart"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ElsePart(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } else { - $result = $res_173; - $this->pos = $pos_173; - unset( $res_173 ); - unset( $pos_173 ); + $result = $res_169; + $this->pos = $pos_169; + unset( $res_169 ); + unset( $pos_169 ); } - $_174 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_174->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_182 = FALSE; break; } + $_170 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_170->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_178 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_177 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_177->expand('end_if') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_182 = FALSE; break; } + $_173 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_173->expand('end_if') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_178 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_180 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_180->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_182 = FALSE; break; } - $_182 = TRUE; break; + $_176 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_176->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_178 = FALSE; break; } + $_178 = TRUE; break; } while(0); - if( $_182 === TRUE ) { + if( $_178 === TRUE ) { return $this->finalise( "If", $result ); } - if( $_182 === FALSE) { return FALSE; } + if( $_178 === FALSE) { return FALSE; } } @@ -1126,282 +1155,282 @@ class SSTemplateParser extends Parser { '}'; } - /* Require: '<%' < 'require' [ Call:(Method:Word "(" < :Arguments > ")") > '%>' */ + /* Require: '<%' < 'require' [ Call:(Method:Word "(" < :CallArguments > ")") > '%>' */ function match_Require ($substack = array()) { $result = $this->construct( "Require" ); - $_202 = NULL; + $_198 = NULL; do { - $_184 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_184->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_202 = FALSE; break; } + $_180 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_180->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_198 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_187 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_187->expand('require') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_202 = FALSE; break; } + $_183 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_183->expand('require') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_198 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_202 = FALSE; break; } + else { $_198 = FALSE; break; } $substack[] = $result; $result = $this->construct( "Call" ); - $_196 = NULL; + $_192 = NULL; do { $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Method" ); } - else { $_196 = FALSE; break; } + else { $_192 = FALSE; break; } if (substr($this->string,$this->pos,1) == "(") { $this->pos += 1; $result["text"] .= "("; } - else { $_196 = FALSE; break; } + else { $_192 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "Arguments"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Arguments(array_merge($substack, array($result))) ) ); + $key = "CallArguments"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_CallArguments(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { - $this->store( $result, $subres, "Arguments" ); + $this->store( $result, $subres, "CallArguments" ); } - else { $_196 = FALSE; break; } + else { $_192 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } if (substr($this->string,$this->pos,1) == ")") { $this->pos += 1; $result["text"] .= ")"; } - else { $_196 = FALSE; break; } - $_196 = TRUE; break; + else { $_192 = FALSE; break; } + $_192 = TRUE; break; } while(0); - if( $_196 === TRUE ) { + if( $_192 === TRUE ) { $subres = $result ; $result = array_pop( $substack ) ; $this->store( $result, $subres, 'Call' ); } - if( $_196 === FALSE) { + if( $_192 === FALSE) { $result = array_pop( $substack ) ; - $_202 = FALSE; break; + $_198 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_200 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_200->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_202 = FALSE; break; } - $_202 = TRUE; break; + $_196 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_196->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_198 = FALSE; break; } + $_198 = TRUE; break; } while(0); - if( $_202 === TRUE ) { + if( $_198 === TRUE ) { return $this->finalise( "Require", $result ); } - if( $_202 === FALSE) { return FALSE; } + if( $_198 === FALSE) { return FALSE; } } function Require_Call(&$res, $sub) { - $res['php'] = "Requirements::".$sub['Method']['text'].'('.$sub['Arguments']['php'].');'; + $res['php'] = "Requirements::".$sub['Method']['text'].'('.$sub['CallArguments']['php'].');'; } /* BlockArguments: :Argument ( < "," < :Argument)* */ function match_BlockArguments ($substack = array()) { $result = $this->construct( "BlockArguments" ); - $_211 = NULL; + $_207 = NULL; do { $key = "Argument"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Argument" ); } - else { $_211 = FALSE; break; } + else { $_207 = FALSE; break; } while (true) { - $res_210 = $result; - $pos_210 = $this->pos; - $_209 = NULL; + $res_206 = $result; + $pos_206 = $this->pos; + $_205 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } if (substr($this->string,$this->pos,1) == ",") { $this->pos += 1; $result["text"] .= ","; } - else { $_209 = FALSE; break; } + else { $_205 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $key = "Argument"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Argument" ); } - else { $_209 = FALSE; break; } - $_209 = TRUE; break; + else { $_205 = FALSE; break; } + $_205 = TRUE; break; } while(0); - if( $_209 === FALSE) { - $result = $res_210; - $this->pos = $pos_210; - unset( $res_210 ); - unset( $pos_210 ); + if( $_205 === FALSE) { + $result = $res_206; + $this->pos = $pos_206; + unset( $res_206 ); + unset( $pos_206 ); break; } } - $_211 = TRUE; break; + $_207 = TRUE; break; } while(0); - if( $_211 === TRUE ) { + if( $_207 === TRUE ) { return $this->finalise( "BlockArguments", $result ); } - if( $_211 === FALSE) { return FALSE; } + if( $_207 === FALSE) { return FALSE; } } /* NotBlockTag: "end_" | (("if" | "else_if" | "else" | "require") ] ) */ function match_NotBlockTag ($substack = array()) { $result = $this->construct( "NotBlockTag" ); - $_238 = NULL; + $_234 = NULL; do { - $res_213 = $result; - $pos_213 = $this->pos; - $_214 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_214->expand("end_") ) ) !== FALSE) { + $res_209 = $result; + $pos_209 = $this->pos; + $_210 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_210->expand("end_") ) ) !== FALSE) { $result["text"] .= $subres; - $_238 = TRUE; break; + $_234 = TRUE; break; } - $result = $res_213; - $this->pos = $pos_213; - $_236 = NULL; + $result = $res_209; + $this->pos = $pos_209; + $_232 = NULL; do { - $_233 = NULL; + $_229 = NULL; do { - $_231 = NULL; + $_227 = NULL; do { - $res_216 = $result; - $pos_216 = $this->pos; - $_217 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_217->expand("if") ) ) !== FALSE) { + $res_212 = $result; + $pos_212 = $this->pos; + $_213 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_213->expand("if") ) ) !== FALSE) { $result["text"] .= $subres; - $_231 = TRUE; break; + $_227 = TRUE; break; } - $result = $res_216; - $this->pos = $pos_216; - $_229 = NULL; + $result = $res_212; + $this->pos = $pos_212; + $_225 = NULL; do { - $res_219 = $result; - $pos_219 = $this->pos; - $_220 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_220->expand("else_if") ) ) !== FALSE) { + $res_215 = $result; + $pos_215 = $this->pos; + $_216 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_216->expand("else_if") ) ) !== FALSE) { $result["text"] .= $subres; - $_229 = TRUE; break; + $_225 = TRUE; break; } - $result = $res_219; - $this->pos = $pos_219; - $_227 = NULL; + $result = $res_215; + $this->pos = $pos_215; + $_223 = NULL; do { - $res_222 = $result; - $pos_222 = $this->pos; - $_223 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_223->expand("else") ) ) !== FALSE) { + $res_218 = $result; + $pos_218 = $this->pos; + $_219 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_219->expand("else") ) ) !== FALSE) { $result["text"] .= $subres; - $_227 = TRUE; break; + $_223 = TRUE; break; } - $result = $res_222; - $this->pos = $pos_222; - $_225 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_225->expand("require") ) ) !== FALSE) { + $result = $res_218; + $this->pos = $pos_218; + $_221 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_221->expand("require") ) ) !== FALSE) { $result["text"] .= $subres; - $_227 = TRUE; break; + $_223 = TRUE; break; } - $result = $res_222; - $this->pos = $pos_222; - $_227 = FALSE; break; + $result = $res_218; + $this->pos = $pos_218; + $_223 = FALSE; break; } while(0); - if( $_227 === TRUE ) { $_229 = TRUE; break; } - $result = $res_219; - $this->pos = $pos_219; - $_229 = FALSE; break; + if( $_223 === TRUE ) { $_225 = TRUE; break; } + $result = $res_215; + $this->pos = $pos_215; + $_225 = FALSE; break; } while(0); - if( $_229 === TRUE ) { $_231 = TRUE; break; } - $result = $res_216; - $this->pos = $pos_216; - $_231 = FALSE; break; + if( $_225 === TRUE ) { $_227 = TRUE; break; } + $result = $res_212; + $this->pos = $pos_212; + $_227 = FALSE; break; } while(0); - if( $_231 === FALSE) { $_233 = FALSE; break; } - $_233 = TRUE; break; + if( $_227 === FALSE) { $_229 = FALSE; break; } + $_229 = TRUE; break; } while(0); - if( $_233 === FALSE) { $_236 = FALSE; break; } + if( $_229 === FALSE) { $_232 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_236 = FALSE; break; } - $_236 = TRUE; break; + else { $_232 = FALSE; break; } + $_232 = TRUE; break; } while(0); - if( $_236 === TRUE ) { $_238 = TRUE; break; } - $result = $res_213; - $this->pos = $pos_213; - $_238 = FALSE; break; + if( $_232 === TRUE ) { $_234 = TRUE; break; } + $result = $res_209; + $this->pos = $pos_209; + $_234 = FALSE; break; } while(0); - if( $_238 === TRUE ) { + if( $_234 === TRUE ) { return $this->finalise( "NotBlockTag", $result ); } - if( $_238 === FALSE) { return FALSE; } + if( $_234 === FALSE) { return FALSE; } } /* ClosedBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > Zap:'%>' :Template? '<%' < 'end_' '$BlockName' > '%>' */ function match_ClosedBlock ($substack = array()) { $result = $this->construct( "ClosedBlock" ); - $_265 = NULL; + $_261 = NULL; do { - $_240 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_240->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_265 = FALSE; break; } + $_236 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_236->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_261 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_243 = $result; - $pos_243 = $this->pos; + $res_239 = $result; + $pos_239 = $this->pos; $key = "NotBlockTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $result = $res_243; - $this->pos = $pos_243; - $_265 = FALSE; break; + $result = $res_239; + $this->pos = $pos_239; + $_261 = FALSE; break; } else { - $result = $res_243; - $this->pos = $pos_243; + $result = $res_239; + $this->pos = $pos_239; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockName" ); } - else { $_265 = FALSE; break; } - $res_249 = $result; - $pos_249 = $this->pos; - $_248 = NULL; + else { $_261 = FALSE; break; } + $res_245 = $result; + $pos_245 = $this->pos; + $_244 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_248 = FALSE; break; } + else { $_244 = FALSE; break; } $key = "BlockArguments"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockArguments" ); } - else { $_248 = FALSE; break; } + else { $_244 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_248 = FALSE; break; } - $_248 = TRUE; break; + else { $_244 = FALSE; break; } + $_244 = TRUE; break; } while(0); - if( $_248 === FALSE) { - $result = $res_249; - $this->pos = $pos_249; - unset( $res_249 ); - unset( $pos_249 ); + if( $_244 === FALSE) { + $result = $res_245; + $this->pos = $pos_245; + unset( $res_245 ); + unset( $pos_245 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $substack[] = $result; $result = $this->construct( "Zap" ); - $_251 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_251->expand('%>') ) ) !== FALSE) { + $_247 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_247->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; $subres = $result ; $result = array_pop( $substack ) ; @@ -1409,46 +1438,61 @@ class SSTemplateParser extends Parser { } else { $result = array_pop( $substack ) ; - $_265 = FALSE; break; + $_261 = FALSE; break; } - $res_254 = $result; - $pos_254 = $this->pos; + $res_250 = $result; + $pos_250 = $this->pos; $key = "Template"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Template" ); } else { - $result = $res_254; - $this->pos = $pos_254; - unset( $res_254 ); - unset( $pos_254 ); + $result = $res_250; + $this->pos = $pos_250; + unset( $res_250 ); + unset( $pos_250 ); } - $_255 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_255->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_265 = FALSE; break; } + $_251 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_251->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_261 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_258 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_258->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_265 = FALSE; break; } - $_260 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_260->expand('$BlockName') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_265 = FALSE; break; } + $_254 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_254->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_261 = FALSE; break; } + $_256 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_256->expand('$BlockName') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_261 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_263 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_263->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_265 = FALSE; break; } - $_265 = TRUE; break; + $_259 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_259->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_261 = FALSE; break; } + $_261 = TRUE; break; } while(0); - if( $_265 === TRUE ) { + if( $_261 === TRUE ) { return $this->finalise( "ClosedBlock", $result ); } - if( $_265 === FALSE) { return FALSE; } + if( $_261 === FALSE) { return FALSE; } } + + /** + * As mentioned in the parser comment, block handling is kept fairly generic for extensibility. The match rule + * builds up two important elements in the match result array: + * 'ArgumentCount' - how many arguments were passed in the opening tag + * 'Arguments' an array of the Argument match rule result arrays + * + * Once a block has successfully been matched against, it will then look for the actual handler, which should + * be on this class (either defined or decorated on) as ClosedBlock_Handler_Name(&$res), where Name is the + * tag name, first letter captialized (i.e Control, Loop, With, etc). + * + * This function will be called with the match rule result array as it's first argument. It should return + * the php result of this block as it's return value, or throw an error if incorrect arguments were passed. + */ + function ClosedBlock__construct(&$res) { $res['ArgumentCount'] = 0; } @@ -1474,6 +1518,9 @@ class SSTemplateParser extends Parser { } } + /** + * This is an example of a block handler function. This one handles the control tag. + */ function ClosedBlock_Handle_Control(&$res) { if ($res['ArgumentCount'] != 1) { throw new SSTemplateParseException('Either no or too many arguments in control block. Must be one argument only.', $this); @@ -1494,66 +1541,66 @@ class SSTemplateParser extends Parser { /* OpenBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > '%>' */ function match_OpenBlock ($substack = array()) { $result = $this->construct( "OpenBlock" ); - $_280 = NULL; + $_276 = NULL; do { - $_267 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_267->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_280 = FALSE; break; } + $_263 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_263->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_276 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_270 = $result; - $pos_270 = $this->pos; + $res_266 = $result; + $pos_266 = $this->pos; $key = "NotBlockTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $result = $res_270; - $this->pos = $pos_270; - $_280 = FALSE; break; + $result = $res_266; + $this->pos = $pos_266; + $_276 = FALSE; break; } else { - $result = $res_270; - $this->pos = $pos_270; + $result = $res_266; + $this->pos = $pos_266; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockName" ); } - else { $_280 = FALSE; break; } - $res_276 = $result; - $pos_276 = $this->pos; - $_275 = NULL; + else { $_276 = FALSE; break; } + $res_272 = $result; + $pos_272 = $this->pos; + $_271 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_275 = FALSE; break; } + else { $_271 = FALSE; break; } $key = "BlockArguments"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockArguments" ); } - else { $_275 = FALSE; break; } + else { $_271 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_275 = FALSE; break; } - $_275 = TRUE; break; + else { $_271 = FALSE; break; } + $_271 = TRUE; break; } while(0); - if( $_275 === FALSE) { - $result = $res_276; - $this->pos = $pos_276; - unset( $res_276 ); - unset( $pos_276 ); + if( $_271 === FALSE) { + $result = $res_272; + $this->pos = $pos_272; + unset( $res_272 ); + unset( $pos_272 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_278 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_278->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_280 = FALSE; break; } - $_280 = TRUE; break; + $_274 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_274->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_276 = FALSE; break; } + $_276 = TRUE; break; } while(0); - if( $_280 === TRUE ) { + if( $_276 === TRUE ) { return $this->finalise( "OpenBlock", $result ); } - if( $_280 === FALSE) { return FALSE; } + if( $_276 === FALSE) { return FALSE; } } @@ -1583,6 +1630,9 @@ class SSTemplateParser extends Parser { } } + /** + * This is an open block handler, for the <% include %> tag + */ function OpenBlock_Handle_Include(&$res) { if ($res['ArgumentCount'] != 1) throw new SSTemplateParseException('Include takes exactly one argument', $this); @@ -1601,6 +1651,9 @@ class SSTemplateParser extends Parser { } } + /** + * This is an open block handler, for the <% debug %> utility tag + */ function OpenBlock_Handle_Debug(&$res) { if ($res['ArgumentCount'] == 0) return 'Debug::show($item);'; else if ($res['ArgumentCount'] == 1) { @@ -1616,11 +1669,17 @@ class SSTemplateParser extends Parser { } } + /** + * This is an open block handler, for the <% base_tag %> tag + */ function OpenBlock_Handle_Base_tag(&$res) { if ($res['ArgumentCount'] != 0) throw new SSTemplateParseException('Base_tag takes no arguments', $this); return '$val .= SSViewer::get_base_tag($val);'; } + /** + * This is an open block handler, for the <% current_page %> tag + */ function OpenBlock_Handle_Current_page(&$res) { if ($res['ArgumentCount'] != 0) throw new SSTemplateParseException('Current_page takes no arguments', $this); return '$val .= $_SERVER[SCRIPT_URL];'; @@ -1629,30 +1688,30 @@ class SSTemplateParser extends Parser { /* MismatchedEndBlock: '<%' < 'end_' Word > '%>' */ function match_MismatchedEndBlock ($substack = array()) { $result = $this->construct( "MismatchedEndBlock" ); - $_291 = NULL; + $_287 = NULL; do { - $_282 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_282->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_291 = FALSE; break; } + $_278 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_278->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_287 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_285 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_285->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_291 = FALSE; break; } + $_281 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_281->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_287 = FALSE; break; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_291 = FALSE; break; } + else { $_287 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_289 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_289->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_291 = FALSE; break; } - $_291 = TRUE; break; + $_285 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_285->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_287 = FALSE; break; } + $_287 = TRUE; break; } while(0); - if( $_291 === TRUE ) { + if( $_287 === TRUE ) { return $this->finalise( "MismatchedEndBlock", $result ); } - if( $_291 === FALSE) { return FALSE; } + if( $_287 === FALSE) { return FALSE; } } @@ -1665,82 +1724,82 @@ class SSTemplateParser extends Parser { /* MalformedOpenTag: '<%' < !NotBlockTag Tag:Word !( ( [ :BlockArguments ] )? > '%>' ) */ function match_MalformedOpenTag ($substack = array()) { $result = $this->construct( "MalformedOpenTag" ); - $_308 = NULL; + $_304 = NULL; do { - $_293 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_293->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_308 = FALSE; break; } + $_289 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_289->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_304 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_296 = $result; - $pos_296 = $this->pos; + $res_292 = $result; + $pos_292 = $this->pos; $key = "NotBlockTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $result = $res_296; - $this->pos = $pos_296; - $_308 = FALSE; break; + $result = $res_292; + $this->pos = $pos_292; + $_304 = FALSE; break; } else { - $result = $res_296; - $this->pos = $pos_296; + $result = $res_292; + $this->pos = $pos_292; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Tag" ); } - else { $_308 = FALSE; break; } - $res_307 = $result; - $pos_307 = $this->pos; - $_306 = NULL; + else { $_304 = FALSE; break; } + $res_303 = $result; + $pos_303 = $this->pos; + $_302 = NULL; do { - $res_302 = $result; - $pos_302 = $this->pos; - $_301 = NULL; + $res_298 = $result; + $pos_298 = $this->pos; + $_297 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_301 = FALSE; break; } + else { $_297 = FALSE; break; } $key = "BlockArguments"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockArguments" ); } - else { $_301 = FALSE; break; } + else { $_297 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_301 = FALSE; break; } - $_301 = TRUE; break; + else { $_297 = FALSE; break; } + $_297 = TRUE; break; } while(0); - if( $_301 === FALSE) { - $result = $res_302; - $this->pos = $pos_302; - unset( $res_302 ); - unset( $pos_302 ); + if( $_297 === FALSE) { + $result = $res_298; + $this->pos = $pos_298; + unset( $res_298 ); + unset( $pos_298 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_304 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_304->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_306 = FALSE; break; } - $_306 = TRUE; break; + $_300 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_300->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_302 = FALSE; break; } + $_302 = TRUE; break; } while(0); - if( $_306 === TRUE ) { - $result = $res_307; - $this->pos = $pos_307; - $_308 = FALSE; break; + if( $_302 === TRUE ) { + $result = $res_303; + $this->pos = $pos_303; + $_304 = FALSE; break; } - if( $_306 === FALSE) { - $result = $res_307; - $this->pos = $pos_307; + if( $_302 === FALSE) { + $result = $res_303; + $this->pos = $pos_303; } - $_308 = TRUE; break; + $_304 = TRUE; break; } while(0); - if( $_308 === TRUE ) { + if( $_304 === TRUE ) { return $this->finalise( "MalformedOpenTag", $result ); } - if( $_308 === FALSE) { return FALSE; } + if( $_304 === FALSE) { return FALSE; } } @@ -1753,64 +1812,64 @@ class SSTemplateParser extends Parser { /* MalformedCloseTag: '<%' < Tag:('end_' :Word ) !( > '%>' ) */ function match_MalformedCloseTag ($substack = array()) { $result = $this->construct( "MalformedCloseTag" ); - $_324 = NULL; + $_320 = NULL; do { - $_310 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_310->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_324 = FALSE; break; } + $_306 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_306->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_320 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $substack[] = $result; $result = $this->construct( "Tag" ); - $_316 = NULL; + $_312 = NULL; do { - $_313 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_313->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_316 = FALSE; break; } + $_309 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_309->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_312 = FALSE; break; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Word" ); } - else { $_316 = FALSE; break; } - $_316 = TRUE; break; + else { $_312 = FALSE; break; } + $_312 = TRUE; break; } while(0); - if( $_316 === TRUE ) { + if( $_312 === TRUE ) { $subres = $result ; $result = array_pop( $substack ) ; $this->store( $result, $subres, 'Tag' ); } - if( $_316 === FALSE) { + if( $_312 === FALSE) { $result = array_pop( $substack ) ; - $_324 = FALSE; break; + $_320 = FALSE; break; } - $res_323 = $result; - $pos_323 = $this->pos; - $_322 = NULL; + $res_319 = $result; + $pos_319 = $this->pos; + $_318 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_320 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_320->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_322 = FALSE; break; } - $_322 = TRUE; break; + $_316 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_316->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_318 = FALSE; break; } + $_318 = TRUE; break; } while(0); - if( $_322 === TRUE ) { - $result = $res_323; - $this->pos = $pos_323; - $_324 = FALSE; break; + if( $_318 === TRUE ) { + $result = $res_319; + $this->pos = $pos_319; + $_320 = FALSE; break; } - if( $_322 === FALSE) { - $result = $res_323; - $this->pos = $pos_323; + if( $_318 === FALSE) { + $result = $res_319; + $this->pos = $pos_319; } - $_324 = TRUE; break; + $_320 = TRUE; break; } while(0); - if( $_324 === TRUE ) { + if( $_320 === TRUE ) { return $this->finalise( "MalformedCloseTag", $result ); } - if( $_324 === FALSE) { return FALSE; } + if( $_320 === FALSE) { return FALSE; } } @@ -1823,33 +1882,33 @@ class SSTemplateParser extends Parser { /* MalformedBlock: MalformedOpenTag | MalformedCloseTag */ function match_MalformedBlock ($substack = array()) { $result = $this->construct( "MalformedBlock" ); - $_329 = NULL; + $_325 = NULL; do { - $res_326 = $result; - $pos_326 = $this->pos; + $res_322 = $result; + $pos_322 = $this->pos; $key = "MalformedOpenTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedOpenTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_329 = TRUE; break; + $_325 = TRUE; break; } - $result = $res_326; - $this->pos = $pos_326; + $result = $res_322; + $this->pos = $pos_322; $key = "MalformedCloseTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedCloseTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_329 = TRUE; break; + $_325 = TRUE; break; } - $result = $res_326; - $this->pos = $pos_326; - $_329 = FALSE; break; + $result = $res_322; + $this->pos = $pos_322; + $_325 = FALSE; break; } while(0); - if( $_329 === TRUE ) { + if( $_325 === TRUE ) { return $this->finalise( "MalformedBlock", $result ); } - if( $_329 === FALSE) { return FALSE; } + if( $_325 === FALSE) { return FALSE; } } @@ -1858,57 +1917,57 @@ class SSTemplateParser extends Parser { /* Comment: "<%--" (!"--%>" /./)+ "--%>" */ function match_Comment ($substack = array()) { $result = $this->construct( "Comment" ); - $_341 = NULL; + $_337 = NULL; do { - $_331 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_331->expand("<%--") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_341 = FALSE; break; } + $_327 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_327->expand("<%--") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_337 = FALSE; break; } $count = 0; while (true) { - $res_338 = $result; - $pos_338 = $this->pos; - $_337 = NULL; + $res_334 = $result; + $pos_334 = $this->pos; + $_333 = NULL; do { - $res_334 = $result; - $pos_334 = $this->pos; - $_333 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_333->expand("--%>") ) ) !== FALSE) { + $res_330 = $result; + $pos_330 = $this->pos; + $_329 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_329->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; - $result = $res_334; - $this->pos = $pos_334; - $_337 = FALSE; break; + $result = $res_330; + $this->pos = $pos_330; + $_333 = FALSE; break; } else { - $result = $res_334; - $this->pos = $pos_334; + $result = $res_330; + $this->pos = $pos_330; } - $_335 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_335->expand('/./') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_337 = FALSE; break; } - $_337 = TRUE; break; + $_331 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_331->expand('/./') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_333 = FALSE; break; } + $_333 = TRUE; break; } while(0); - if( $_337 === FALSE) { - $result = $res_338; - $this->pos = $pos_338; - unset( $res_338 ); - unset( $pos_338 ); + if( $_333 === FALSE) { + $result = $res_334; + $this->pos = $pos_334; + unset( $res_334 ); + unset( $pos_334 ); break; } $count += 1; } if ($count > 0) { } - else { $_341 = FALSE; break; } - $_339 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_339->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_341 = FALSE; break; } - $_341 = TRUE; break; + else { $_337 = FALSE; break; } + $_335 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_335->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_337 = FALSE; break; } + $_337 = TRUE; break; } while(0); - if( $_341 === TRUE ) { + if( $_337 === TRUE ) { return $this->finalise( "Comment", $result ); } - if( $_341 === FALSE) { return FALSE; } + if( $_337 === FALSE) { return FALSE; } } @@ -1929,8 +1988,8 @@ class SSTemplateParser extends Parser { / */ function match_Text ($substack = array()) { $result = array("name"=>"Text", "text"=>""); - $_343 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_343->expand('/ + $_339 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_339->expand('/ ( (\\\\.) | # Any escaped character ([^<${]) | # Any character that isn\'t <, $ or { @@ -1952,150 +2011,150 @@ class SSTemplateParser extends Parser { $result = $this->construct( "Template" ); $count = 0; while (true) { - $res_375 = $result; - $pos_375 = $this->pos; - $_374 = NULL; + $res_371 = $result; + $pos_371 = $this->pos; + $_370 = NULL; do { - $_372 = NULL; + $_368 = NULL; do { - $res_345 = $result; - $pos_345 = $this->pos; + $res_341 = $result; + $pos_341 = $this->pos; $key = "Comment"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comment(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_372 = TRUE; break; + $_368 = TRUE; break; } - $result = $res_345; - $this->pos = $pos_345; - $_370 = NULL; + $result = $res_341; + $this->pos = $pos_341; + $_366 = NULL; do { - $res_347 = $result; - $pos_347 = $this->pos; + $res_343 = $result; + $pos_343 = $this->pos; $key = "If"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_If(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_370 = TRUE; break; + $_366 = TRUE; break; } - $result = $res_347; - $this->pos = $pos_347; - $_368 = NULL; + $result = $res_343; + $this->pos = $pos_343; + $_364 = NULL; do { - $res_349 = $result; - $pos_349 = $this->pos; + $res_345 = $result; + $pos_345 = $this->pos; $key = "Require"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Require(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_368 = TRUE; break; + $_364 = TRUE; break; } - $result = $res_349; - $this->pos = $pos_349; - $_366 = NULL; + $result = $res_345; + $this->pos = $pos_345; + $_362 = NULL; do { - $res_351 = $result; - $pos_351 = $this->pos; + $res_347 = $result; + $pos_347 = $this->pos; $key = "ClosedBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_366 = TRUE; break; + $_362 = TRUE; break; } - $result = $res_351; - $this->pos = $pos_351; - $_364 = NULL; + $result = $res_347; + $this->pos = $pos_347; + $_360 = NULL; do { - $res_353 = $result; - $pos_353 = $this->pos; + $res_349 = $result; + $pos_349 = $this->pos; $key = "OpenBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_364 = TRUE; break; + $_360 = TRUE; break; } - $result = $res_353; - $this->pos = $pos_353; - $_362 = NULL; + $result = $res_349; + $this->pos = $pos_349; + $_358 = NULL; do { - $res_355 = $result; - $pos_355 = $this->pos; + $res_351 = $result; + $pos_351 = $this->pos; $key = "MalformedBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_362 = TRUE; break; + $_358 = TRUE; break; } - $result = $res_355; - $this->pos = $pos_355; - $_360 = NULL; + $result = $res_351; + $this->pos = $pos_351; + $_356 = NULL; do { - $res_357 = $result; - $pos_357 = $this->pos; + $res_353 = $result; + $pos_353 = $this->pos; $key = "Injection"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_360 = TRUE; break; + $_356 = TRUE; break; } - $result = $res_357; - $this->pos = $pos_357; + $result = $res_353; + $this->pos = $pos_353; $key = "Text"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_360 = TRUE; break; + $_356 = TRUE; break; } - $result = $res_357; - $this->pos = $pos_357; - $_360 = FALSE; break; + $result = $res_353; + $this->pos = $pos_353; + $_356 = FALSE; break; } while(0); - if( $_360 === TRUE ) { $_362 = TRUE; break; } - $result = $res_355; - $this->pos = $pos_355; - $_362 = FALSE; break; + if( $_356 === TRUE ) { $_358 = TRUE; break; } + $result = $res_351; + $this->pos = $pos_351; + $_358 = FALSE; break; } while(0); - if( $_362 === TRUE ) { $_364 = TRUE; break; } - $result = $res_353; - $this->pos = $pos_353; - $_364 = FALSE; break; + if( $_358 === TRUE ) { $_360 = TRUE; break; } + $result = $res_349; + $this->pos = $pos_349; + $_360 = FALSE; break; } while(0); - if( $_364 === TRUE ) { $_366 = TRUE; break; } - $result = $res_351; - $this->pos = $pos_351; - $_366 = FALSE; break; + if( $_360 === TRUE ) { $_362 = TRUE; break; } + $result = $res_347; + $this->pos = $pos_347; + $_362 = FALSE; break; } while(0); - if( $_366 === TRUE ) { $_368 = TRUE; break; } - $result = $res_349; - $this->pos = $pos_349; - $_368 = FALSE; break; + if( $_362 === TRUE ) { $_364 = TRUE; break; } + $result = $res_345; + $this->pos = $pos_345; + $_364 = FALSE; break; } while(0); - if( $_368 === TRUE ) { $_370 = TRUE; break; } - $result = $res_347; - $this->pos = $pos_347; - $_370 = FALSE; break; + if( $_364 === TRUE ) { $_366 = TRUE; break; } + $result = $res_343; + $this->pos = $pos_343; + $_366 = FALSE; break; } while(0); - if( $_370 === TRUE ) { $_372 = TRUE; break; } - $result = $res_345; - $this->pos = $pos_345; - $_372 = FALSE; break; + if( $_366 === TRUE ) { $_368 = TRUE; break; } + $result = $res_341; + $this->pos = $pos_341; + $_368 = FALSE; break; } while(0); - if( $_372 === FALSE) { $_374 = FALSE; break; } - $_374 = TRUE; break; + if( $_368 === FALSE) { $_370 = FALSE; break; } + $_370 = TRUE; break; } while(0); - if( $_374 === FALSE) { - $result = $res_375; - $this->pos = $pos_375; - unset( $res_375 ); - unset( $pos_375 ); + if( $_370 === FALSE) { + $result = $res_371; + $this->pos = $pos_371; + unset( $res_371 ); + unset( $pos_371 ); break; } $count += 1; @@ -2138,168 +2197,168 @@ class SSTemplateParser extends Parser { $result = $this->construct( "TopTemplate" ); $count = 0; while (true) { - $res_410 = $result; - $pos_410 = $this->pos; - $_409 = NULL; + $res_406 = $result; + $pos_406 = $this->pos; + $_405 = NULL; do { - $_407 = NULL; + $_403 = NULL; do { - $res_376 = $result; - $pos_376 = $this->pos; + $res_372 = $result; + $pos_372 = $this->pos; $key = "Comment"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comment(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_407 = TRUE; break; + $_403 = TRUE; break; } - $result = $res_376; - $this->pos = $pos_376; - $_405 = NULL; + $result = $res_372; + $this->pos = $pos_372; + $_401 = NULL; do { - $res_378 = $result; - $pos_378 = $this->pos; + $res_374 = $result; + $pos_374 = $this->pos; $key = "If"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_If(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_405 = TRUE; break; + $_401 = TRUE; break; } - $result = $res_378; - $this->pos = $pos_378; - $_403 = NULL; + $result = $res_374; + $this->pos = $pos_374; + $_399 = NULL; do { - $res_380 = $result; - $pos_380 = $this->pos; + $res_376 = $result; + $pos_376 = $this->pos; $key = "Require"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Require(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_403 = TRUE; break; + $_399 = TRUE; break; } - $result = $res_380; - $this->pos = $pos_380; - $_401 = NULL; + $result = $res_376; + $this->pos = $pos_376; + $_397 = NULL; do { - $res_382 = $result; - $pos_382 = $this->pos; + $res_378 = $result; + $pos_378 = $this->pos; $key = "ClosedBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_401 = TRUE; break; + $_397 = TRUE; break; } - $result = $res_382; - $this->pos = $pos_382; - $_399 = NULL; + $result = $res_378; + $this->pos = $pos_378; + $_395 = NULL; do { - $res_384 = $result; - $pos_384 = $this->pos; + $res_380 = $result; + $pos_380 = $this->pos; $key = "OpenBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_399 = TRUE; break; + $_395 = TRUE; break; } - $result = $res_384; - $this->pos = $pos_384; - $_397 = NULL; + $result = $res_380; + $this->pos = $pos_380; + $_393 = NULL; do { - $res_386 = $result; - $pos_386 = $this->pos; + $res_382 = $result; + $pos_382 = $this->pos; $key = "MalformedBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_397 = TRUE; break; + $_393 = TRUE; break; } - $result = $res_386; - $this->pos = $pos_386; - $_395 = NULL; + $result = $res_382; + $this->pos = $pos_382; + $_391 = NULL; do { - $res_388 = $result; - $pos_388 = $this->pos; + $res_384 = $result; + $pos_384 = $this->pos; $key = "MismatchedEndBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MismatchedEndBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_395 = TRUE; break; + $_391 = TRUE; break; } - $result = $res_388; - $this->pos = $pos_388; - $_393 = NULL; + $result = $res_384; + $this->pos = $pos_384; + $_389 = NULL; do { - $res_390 = $result; - $pos_390 = $this->pos; + $res_386 = $result; + $pos_386 = $this->pos; $key = "Injection"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_393 = TRUE; break; + $_389 = TRUE; break; } - $result = $res_390; - $this->pos = $pos_390; + $result = $res_386; + $this->pos = $pos_386; $key = "Text"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_393 = TRUE; break; + $_389 = TRUE; break; } - $result = $res_390; - $this->pos = $pos_390; - $_393 = FALSE; break; + $result = $res_386; + $this->pos = $pos_386; + $_389 = FALSE; break; } while(0); - if( $_393 === TRUE ) { $_395 = TRUE; break; } - $result = $res_388; - $this->pos = $pos_388; - $_395 = FALSE; break; + if( $_389 === TRUE ) { $_391 = TRUE; break; } + $result = $res_384; + $this->pos = $pos_384; + $_391 = FALSE; break; } while(0); - if( $_395 === TRUE ) { $_397 = TRUE; break; } - $result = $res_386; - $this->pos = $pos_386; - $_397 = FALSE; break; + if( $_391 === TRUE ) { $_393 = TRUE; break; } + $result = $res_382; + $this->pos = $pos_382; + $_393 = FALSE; break; } while(0); - if( $_397 === TRUE ) { $_399 = TRUE; break; } - $result = $res_384; - $this->pos = $pos_384; - $_399 = FALSE; break; + if( $_393 === TRUE ) { $_395 = TRUE; break; } + $result = $res_380; + $this->pos = $pos_380; + $_395 = FALSE; break; } while(0); - if( $_399 === TRUE ) { $_401 = TRUE; break; } - $result = $res_382; - $this->pos = $pos_382; - $_401 = FALSE; break; + if( $_395 === TRUE ) { $_397 = TRUE; break; } + $result = $res_378; + $this->pos = $pos_378; + $_397 = FALSE; break; } while(0); - if( $_401 === TRUE ) { $_403 = TRUE; break; } - $result = $res_380; - $this->pos = $pos_380; - $_403 = FALSE; break; + if( $_397 === TRUE ) { $_399 = TRUE; break; } + $result = $res_376; + $this->pos = $pos_376; + $_399 = FALSE; break; } while(0); - if( $_403 === TRUE ) { $_405 = TRUE; break; } - $result = $res_378; - $this->pos = $pos_378; - $_405 = FALSE; break; + if( $_399 === TRUE ) { $_401 = TRUE; break; } + $result = $res_374; + $this->pos = $pos_374; + $_401 = FALSE; break; } while(0); - if( $_405 === TRUE ) { $_407 = TRUE; break; } - $result = $res_376; - $this->pos = $pos_376; - $_407 = FALSE; break; + if( $_401 === TRUE ) { $_403 = TRUE; break; } + $result = $res_372; + $this->pos = $pos_372; + $_403 = FALSE; break; } while(0); - if( $_407 === FALSE) { $_409 = FALSE; break; } - $_409 = TRUE; break; + if( $_403 === FALSE) { $_405 = FALSE; break; } + $_405 = TRUE; break; } while(0); - if( $_409 === FALSE) { - $result = $res_410; - $this->pos = $pos_410; - unset( $res_410 ); - unset( $pos_410 ); + if( $_405 === FALSE) { + $result = $res_406; + $this->pos = $pos_406; + unset( $res_406 ); + unset( $pos_406 ); break; } $count += 1; @@ -2312,25 +2371,51 @@ class SSTemplateParser extends Parser { + + /** + * The TopTemplate also includes the opening stanza to start off the template + */ function TopTemplate__construct(&$res) { $res['php'] = "Template_Text($res, $sub); } function TopTemplate_STR(&$res, $sub) { return $this->Template_STR($res, $sub); } + + /****************** + * Here ends the parser itself. Below are utility methods to use the parser + */ + + /** + * Compiles some passed template source code into the php code that will execute as per the template source. + * + * @static + * @throws SSTemplateParseException + * @param $string - The source of the template + * @param string $templateName - The name of the template, normally the filename the template source was loaded from + * @param bool $includeDebuggingComments - True is debugging comments should be included in the output + * @return mixed|string - The php that, when executed (via include or exec) will behave as per the template source + */ static function compileString($string, $templateName = "", $includeDebuggingComments=false) { + // Construct a parser instance $parser = new SSTemplateParser($string); $parser->includeDebuggingComments = $includeDebuggingComments; // Ignore UTF8 BOM at begining of string. TODO: Confirm this is needed, make sure SSViewer handles UTF (and other encodings) properly if(substr($string, 0,3) == pack("CCC", 0xef, 0xbb, 0xbf)) $parser->pos = 3; + // Match the source against the parser $result = $parser->match_TopTemplate(); if(!$result) throw new SSTemplateParseException('Unexpected problem parsing template', $parser); + // Get the result $code = $result['php']; + // Include top level debugging comments if desired if($includeDebuggingComments && $templateName && stripos($code, " + +Block: One of two SS template structures. The special characters "<%" and "%>" are used to wrap the opening and +(required or forbidden depending on which block exactly) closing block marks. + +Open Block: An SS template block that doesn't wrap any content or have a closing end tag (in fact, a closing end tag is +forbidden) + +Closed Block: An SS template block that wraps content, and requires a counterpart <% end_blockname %> tag + */ class SSTemplateParser extends Parser { + /** + * @var bool - Set true by SSTemplateParser::compileString if the template should include comments intended + * for debugging (template source, included files, etc) + */ protected $includeDebuggingComments = false; function construct($name) { @@ -67,11 +93,17 @@ class SSTemplateParser extends Parser { Number: / [0-9]+ / Value: / [A-Za-z0-9_]+ / - Arguments: :Argument ( < "," < :Argument )* - */ + # CallArguments is a list of one or more comma seperated "arguments" (lookups or strings, either bare or marked) + # as passed to a Call within brackets + + CallArguments: :Argument ( < "," < :Argument )* + */ - /** Values are bare words in templates, but strings in PHP. We rely on PHP's type conversion to back-convert strings to numbers when needed */ - function Arguments_Argument(&$res, $sub) { + /** + * Values are bare words in templates, but strings in PHP. We rely on PHP's type conversion to back-convert strings + * to numbers when needed. + */ + function CallArguments_Argument(&$res, $sub) { if (isset($res['php'])) $res['php'] .= ', '; else $res['php'] = ''; @@ -79,8 +111,16 @@ class SSTemplateParser extends Parser { } /*!* - Call: Method:Word ( "(" < :Arguments? > ")" )? + + # Call is a php-style function call, e.g. Method(Argument, ...). Unlike PHP, the brackets are optional if no + # arguments are passed + + Call: Method:Word ( "(" < :CallArguments? > ")" )? + # A lookup is a lookup of a value on the current scope object. It's a sequence of calls seperated by "." characters + # This final call in the sequence needs handling specially, as different structures need different sorts of values, + # which require a different final method to be called to get the right return value + LookupStep: :Call &"." LastLookupStep: :Call @@ -92,12 +132,17 @@ class SSTemplateParser extends Parser { $res['LookupSteps'] = array(); } + /** + * The basic generated PHP of LookupStep and LastLookupStep is the same, except that LookupStep calls 'obj' to + * get the next ViewableData in the sequence, and LastLookupStep calls different methods (XML_val, hasValue, obj) + * depending on the context the lookup is used in. + */ function Lookup_AddLookupStep(&$res, $sub, $method) { $res['LookupSteps'][] = $sub; $property = $sub['Call']['Method']['text']; - if (isset($sub['Call']['Arguments']) && $arguments = $sub['Call']['Arguments']['php']) { + if (isset($sub['Call']['CallArguments']) && $arguments = $sub['Call']['CallArguments']['php']) { $res['php'] .= "->$method('$property', array($arguments), true)"; } else { @@ -114,6 +159,10 @@ class SSTemplateParser extends Parser { } /*!* + + # Injections are where, outside of a block, a value needs to be inserted into the output. You can either + # just do $Foo, or {$Foo} if the surrounding text would cause a problem (e.g. {$Foo}Bar) + SimpleInjection: '$' :Lookup BracketInjection: '{$' :Lookup "}" Injection: BracketInjection | SimpleInjection @@ -123,23 +172,57 @@ class SSTemplateParser extends Parser { } /*!* - DollarMarkedLookup: BracketInjection | SimpleInjection + + # Inside a block's arguments you can still use the same format as a simple injection ($Foo). In this case + # it marks the argument as being a lookup, not a string (if it was bare it might still be used as a lookup, + # but that depends on where it's used, a la 2.4) + + DollarMarkedLookup: SimpleInjection */ function DollarMarkedLookup_STR(&$res, $sub) { $res['Lookup'] = $sub['Lookup']; } /*!* + + # Inside a block's arguments you can explictly mark a string by surrounding it with quotes (single or double, + # but they must be matching). If you do, inside the quote you can escape any character, but the only character + # that _needs_ escaping is the matching closing quote + QuotedString: q:/['"]/ String:/ (\\\\ | \\. | [^$q\\])* / '$q' + # In order to support 2.4's base syntax, we also need to detect free strings - strings not surrounded by + # quotes, and containing spaces or punctuation, but supported as a single string. We support almost as flexible + # a string as 2.4 - we don't attempt to determine the closing character by context, but just break on any character + # which, in some context, would indicate the end of a free string, regardless of if we're actually in that context + # or not + FreeString: /[^,)%!=|&]+/ + # An argument - either a marked value, or a bare value, prefering lookup matching on the bare value over freestring + # matching as long as that would give a successful parse + Argument: :DollarMarkedLookup | :QuotedString | :Lookup !(< FreeString)| :FreeString */ + + /** + * If we get a bare value, we don't know enough to determine exactly what php would be the translation, because + * we don't know if the position of use indicates a lookup or a string argument. + * + * Instead, we record 'ArgumentMode' as a member of this matches results node, which can be: + * - lookup if this argument was unambiguously a lookup (marked as such) + * - string is this argument was unambiguously a string (marked as such, or impossible to parse as lookup) + * - default if this argument needs to be handled as per 2.4 + * + * In the case of 'default', there is no php member of the results node, but instead 'lookup_php', which + * should be used by the parent if the context indicates a lookup, and 'string_php' which should be used + * if the context indicates a string + */ + function Argument_DollarMarkedLookup(&$res, $sub) { $res['ArgumentMode'] = 'lookup'; $res['php'] = $sub['Lookup']['php']; @@ -168,6 +251,9 @@ class SSTemplateParser extends Parser { } /*!* + + # if and else_if blocks allow basic comparisons between arguments + ComparisonOperator: "==" | "!=" | "=" Comparison: Argument < ComparisonOperator > Argument @@ -188,6 +274,11 @@ class SSTemplateParser extends Parser { } /*!* + + # If a comparison operator is not used in an if or else_if block, then the statement is a 'presence check', + # which checks if the argument given is present or not. For explicit strings (which were not allowed in 2.4) + # this falls back to simple truthiness check + PresenceCheck: Argument */ function PresenceCheck_Argument(&$res, $sub) { @@ -203,15 +294,24 @@ class SSTemplateParser extends Parser { } /*!* + + # if and else_if arguments are a series of presence checks and comparisons, optionally seperated by boolean + # operators + IfArgumentPortion: Comparison | PresenceCheck */ function IfArgumentPortion_STR(&$res, $sub) { $res['php'] = $sub['php']; } - /*!* + /*!* + + # if and else_if arguments can be combined via these two boolean operators. No precendence overriding is supported + BooleanOperator: "||" | "&&" + # This is the combination of the previous if and else_if argument portions + IfArgument: :IfArgumentPortion ( < :BooleanOperator < :IfArgumentPortion )* */ function IfArgument__construct(&$res){ @@ -226,6 +326,11 @@ class SSTemplateParser extends Parser { } /*!* + + # ifs are handled seperately from other closed block tags, because (A) their structure is different - they + # can have else_if and else tags in between the if tag and the end_if tag, and (B) they have a different + # argument structure to every other block + IfPart: '<%' < 'if' < :IfArgument > '%>' :Template? ElseIfPart: '<%' < 'else_if' < :IfArgument > '%>' :Template? ElsePart: '<%' < 'else' > '%>' :Template? @@ -254,19 +359,50 @@ class SSTemplateParser extends Parser { } /*!* - Require: '<%' < 'require' [ Call:(Method:Word "(" < :Arguments > ")") > '%>' + + # The require block is handled seperately to the other open blocks as the argument syntax is different + # - must have one call style argument, must pass arguments to that call style argument + + Require: '<%' < 'require' [ Call:(Method:Word "(" < :CallArguments > ")") > '%>' */ function Require_Call(&$res, $sub) { - $res['php'] = "Requirements::".$sub['Method']['text'].'('.$sub['Arguments']['php'].');'; + $res['php'] = "Requirements::".$sub['Method']['text'].'('.$sub['CallArguments']['php'].');'; } /*!* + + # To make the block support reasonably extendable, we don't explicitly define each closed block and it's structure, + # but instead match against a generic <% block_name argument, ... %> pattern. Each argument is left as per the + # output of the Argument matcher, and the handler (see the PHPDoc block later for more on this) is responsible + # for pulling out the info required + BlockArguments: :Argument ( < "," < :Argument)* + # NotBlockTag matches against any word that might come after a "<%" that the generic open and closed block handlers + # shouldn't attempt to match against, because they're handled by more explicit matchers + NotBlockTag: "end_" | (("if" | "else_if" | "else" | "require") ] ) + # Match against closed blocks - blocks with an opening and a closing tag that surround some internal portion of + # template + ClosedBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > Zap:'%>' :Template? '<%' < 'end_' '$BlockName' > '%>' */ + + /** + * As mentioned in the parser comment, block handling is kept fairly generic for extensibility. The match rule + * builds up two important elements in the match result array: + * 'ArgumentCount' - how many arguments were passed in the opening tag + * 'Arguments' an array of the Argument match rule result arrays + * + * Once a block has successfully been matched against, it will then look for the actual handler, which should + * be on this class (either defined or decorated on) as ClosedBlock_Handler_Name(&$res), where Name is the + * tag name, first letter captialized (i.e Control, Loop, With, etc). + * + * This function will be called with the match rule result array as it's first argument. It should return + * the php result of this block as it's return value, or throw an error if incorrect arguments were passed. + */ + function ClosedBlock__construct(&$res) { $res['ArgumentCount'] = 0; } @@ -292,6 +428,9 @@ class SSTemplateParser extends Parser { } } + /** + * This is an example of a block handler function. This one handles the control tag. + */ function ClosedBlock_Handle_Control(&$res) { if ($res['ArgumentCount'] != 1) { throw new SSTemplateParseException('Either no or too many arguments in control block. Must be one argument only.', $this); @@ -310,6 +449,10 @@ class SSTemplateParser extends Parser { } /*!* + + # Open blocks are handled in the same generic manner as closed blocks. There is no need to define which blocks + # are which - closed is tried first, and if no matching end tag is found, open is tried next + OpenBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > '%>' */ function OpenBlock__construct(&$res) { @@ -337,6 +480,9 @@ class SSTemplateParser extends Parser { } } + /** + * This is an open block handler, for the <% include %> tag + */ function OpenBlock_Handle_Include(&$res) { if ($res['ArgumentCount'] != 1) throw new SSTemplateParseException('Include takes exactly one argument', $this); @@ -355,6 +501,9 @@ class SSTemplateParser extends Parser { } } + /** + * This is an open block handler, for the <% debug %> utility tag + */ function OpenBlock_Handle_Debug(&$res) { if ($res['ArgumentCount'] == 0) return 'Debug::show($item);'; else if ($res['ArgumentCount'] == 1) { @@ -370,17 +519,28 @@ class SSTemplateParser extends Parser { } } + /** + * This is an open block handler, for the <% base_tag %> tag + */ function OpenBlock_Handle_Base_tag(&$res) { if ($res['ArgumentCount'] != 0) throw new SSTemplateParseException('Base_tag takes no arguments', $this); return '$val .= SSViewer::get_base_tag($val);'; } + /** + * This is an open block handler, for the <% current_page %> tag + */ function OpenBlock_Handle_Current_page(&$res) { if ($res['ArgumentCount'] != 0) throw new SSTemplateParseException('Current_page takes no arguments', $this); return '$val .= $_SERVER[SCRIPT_URL];'; } /*!* + + # This is used to detect when we have a mismatched closing tag (i.e., one with no equivilent opening tag) + # Because of parser limitations, this can only be used at the top nesting level of a template. Other mismatched + # closing tags are detected as an invalid open tag + MismatchedEndBlock: '<%' < 'end_' Word > '%>' */ function MismatchedEndBlock__finalise(&$res) { @@ -389,6 +549,10 @@ class SSTemplateParser extends Parser { } /*!* + + # This is used to detect a malformed opening tag - one where the tag is opened with the "<%" characters, but + # the tag is not structured properly + MalformedOpenTag: '<%' < !NotBlockTag Tag:Word !( ( [ :BlockArguments ] )? > '%>' ) */ function MalformedOpenTag__finalise(&$res) { @@ -397,6 +561,10 @@ class SSTemplateParser extends Parser { } /*!* + + # This is used to detect a malformed end tag - one where the tag is opened with the "<%" characters, but + # the tag is not structured properly + MalformedCloseTag: '<%' < Tag:('end_' :Word ) !( > '%>' ) */ function MalformedCloseTag__finalise(&$res) { @@ -405,10 +573,16 @@ class SSTemplateParser extends Parser { } /*!* + + # This is used to detect a malformed tag. It's mostly to keep the Template match rule a bit shorter + MalformedBlock: MalformedOpenTag | MalformedCloseTag */ /*!* + + # This is used to remove template comments + Comment: "<%--" (!"--%>" /./)+ "--%>" */ function Comment__construct(&$res) { @@ -416,6 +590,9 @@ class SSTemplateParser extends Parser { } /*!* + + # Text matches anything that isn't a template command (not an injection, block of any kind or comment) + Text: / ( (\\.) | # Any escaped character @@ -427,6 +604,9 @@ class SSTemplateParser extends Parser { )+ / + # Template is any structurally-complete portion of template (a full nested level in other words). It's used + # by the block rules to recurse + Template: (Comment | If | Require | ClosedBlock | OpenBlock | MalformedBlock | Injection | Text)+ */ function Template__construct(&$res) { @@ -455,27 +635,57 @@ class SSTemplateParser extends Parser { } /*!* + + # TopTemplate is the same as Template, but should only be used at the top level (not nested), as it includes + # MismatchedEndBlock detection, which only works at the top level + TopTemplate: (Comment | If | Require | ClosedBlock | OpenBlock | MalformedBlock | MismatchedEndBlock | Injection | Text)+ */ + + /** + * The TopTemplate also includes the opening stanza to start off the template + */ function TopTemplate__construct(&$res) { $res['php'] = "Template_Text($res, $sub); } function TopTemplate_STR(&$res, $sub) { return $this->Template_STR($res, $sub); } + + /****************** + * Here ends the parser itself. Below are utility methods to use the parser + */ + + /** + * Compiles some passed template source code into the php code that will execute as per the template source. + * + * @static + * @throws SSTemplateParseException + * @param $string - The source of the template + * @param string $templateName - The name of the template, normally the filename the template source was loaded from + * @param bool $includeDebuggingComments - True is debugging comments should be included in the output + * @return mixed|string - The php that, when executed (via include or exec) will behave as per the template source + */ static function compileString($string, $templateName = "", $includeDebuggingComments=false) { + // Construct a parser instance $parser = new SSTemplateParser($string); $parser->includeDebuggingComments = $includeDebuggingComments; // Ignore UTF8 BOM at begining of string. TODO: Confirm this is needed, make sure SSViewer handles UTF (and other encodings) properly if(substr($string, 0,3) == pack("CCC", 0xef, 0xbb, 0xbf)) $parser->pos = 3; + // Match the source against the parser $result = $parser->match_TopTemplate(); if(!$result) throw new SSTemplateParseException('Unexpected problem parsing template', $parser); + // Get the result $code = $result['php']; + // Include top level debugging comments if desired if($includeDebuggingComments && $templateName && stripos($code, " Date: Fri, 18 Feb 2011 17:06:11 +1300 Subject: [PATCH 07/15] ENHANCEMENT: Add Up support --- core/SSTemplateParser.php | 64 ++++++++++------ core/SSTemplateParser.php.inc | 64 ++++++++++------ core/SSViewer.php | 135 ++++++++++++++++++++++++++++++++-- tests/SSViewerTest.php | 131 +++++++++++++++++++++++++++++++++ 4 files changed, 346 insertions(+), 48 deletions(-) diff --git a/core/SSTemplateParser.php b/core/SSTemplateParser.php index 3e9b7a0d3..0094a21eb 100644 --- a/core/SSTemplateParser.php +++ b/core/SSTemplateParser.php @@ -67,12 +67,6 @@ class SSTemplateParser extends Parser { */ protected $includeDebuggingComments = false; - function construct($name) { - $result = parent::construct($name); - $result['tags'] = array(); - return $result; - } - /* Word: / [A-Za-z_] [A-Za-z0-9_]* / */ function match_Word ($substack = array()) { $result = array("name"=>"Word", "text"=>""); @@ -169,7 +163,7 @@ class SSTemplateParser extends Parser { if (isset($res['php'])) $res['php'] .= ', '; else $res['php'] = ''; - $res['php'] .= ($sub['ArgumentMode'] == 'default') ? $sub['string_php'] : $sub['php']; + $res['php'] .= ($sub['ArgumentMode'] == 'default') ? $sub['string_php'] : str_replace('$$FINAL', 'XML_val', $sub['php']); } /* Call: Method:Word ( "(" < :CallArguments? > ")" )? */ @@ -354,7 +348,7 @@ class SSTemplateParser extends Parser { function Lookup__construct(&$res) { - $res['php'] = '$item'; + $res['php'] = '$scope'; $res['LookupSteps'] = array(); } @@ -381,7 +375,7 @@ class SSTemplateParser extends Parser { } function Lookup_LastLookupStep(&$res, $sub) { - $this->Lookup_AddLookupStep($res, $sub, 'XML_val'); + $this->Lookup_AddLookupStep($res, $sub, '$$FINAL'); } /* SimpleInjection: '$' :Lookup */ @@ -474,7 +468,7 @@ class SSTemplateParser extends Parser { function Injection_STR(&$res, $sub) { - $res['php'] = '$val .= '. $sub['Lookup']['php'] . ';'; + $res['php'] = '$val .= '. str_replace('$$FINAL', 'XML_val', $sub['Lookup']['php']) . ';'; } /* DollarMarkedLookup: SimpleInjection */ @@ -777,11 +771,11 @@ class SSTemplateParser extends Parser { function Comparison_Argument(&$res, $sub) { if ($sub['ArgumentMode'] == 'default') { if (isset($res['php'])) $res['php'] .= $sub['string_php']; - else $res['php'] = $sub['lookup_php']; + else $res['php'] = str_replace('$$FINAL', 'XML_val', $sub['lookup_php']); } else { if (!isset($res['php'])) $res['php'] = ''; - $res['php'] .= $sub['php']; + $res['php'] .= str_replace('$$FINAL', 'XML_val', $sub['php']); } } @@ -811,7 +805,7 @@ class SSTemplateParser extends Parser { $php = ($sub['ArgumentMode'] == 'default' ? $sub['lookup_php'] : $sub['php']); // TODO: kinda hacky - maybe we need a way to pass state down the parse chain so // Lookup_LastLookupStep and Argument_BareWord can produce hasValue instead of XML_val - $res['php'] = str_replace('->XML_val', '->hasValue', $php); + $res['php'] = str_replace('$$FINAL', 'hasValue', $php); } } @@ -1519,9 +1513,9 @@ class SSTemplateParser extends Parser { } /** - * This is an example of a block handler function. This one handles the control tag. + * This is an example of a block handler function. This one handles the loop tag. */ - function ClosedBlock_Handle_Control(&$res) { + function ClosedBlock_Handle_Loop(&$res) { if ($res['ArgumentCount'] != 1) { throw new SSTemplateParseException('Either no or too many arguments in control block. Must be one argument only.', $this); } @@ -1531,11 +1525,39 @@ class SSTemplateParser extends Parser { throw new SSTemplateParseException('Control block cant take string as argument.', $this); } - $on = str_replace('->XML_val', '->obj', ($arg['ArgumentMode'] == 'default') ? $arg['lookup_php'] : $arg['php']); + $on = str_replace('$$FINAL', 'obj', ($arg['ArgumentMode'] == 'default') ? $arg['lookup_php'] : $arg['php']); return - 'array_push($itemStack, $item); if($loop = '.$on.') foreach($loop as $key => $item) {' . PHP_EOL . + $on . '; $scope->pushScope(); while (($key = $scope->next()) !== false) {' . PHP_EOL . $res['Template']['php'] . PHP_EOL . - '} $item = array_pop($itemStack); '; + '}; $scope->popScope(); '; + } + + /** + * The deprecated closed block handler for control blocks + * @deprecated + */ + function ClosedBlock_Handle_Control(&$res) { + return $this->ClosedBlock_Handle_Loop($res); + } + + /** + * The closed block handler for with blocks + */ + function ClosedBlock_Handle_With(&$res) { + if ($res['ArgumentCount'] != 1) { + throw new SSTemplateParseException('Either no or too many arguments in with block. Must be one argument only.', $this); + } + + $arg = $res['Arguments'][0]; + if ($arg['ArgumentMode'] == 'string') { + throw new SSTemplateParseException('Control block cant take string as argument.', $this); + } + + $on = str_replace('$$FINAL', 'obj', ($arg['ArgumentMode'] == 'default') ? $arg['lookup_php'] : $arg['php']); + return + $on . '; $scope->pushScope();' . PHP_EOL . + $res['Template']['php'] . PHP_EOL . + '; $scope->popScope(); '; } /* OpenBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > '%>' */ @@ -1642,12 +1664,12 @@ class SSTemplateParser extends Parser { if($this->includeDebuggingComments) { // Add include filename comments on dev sites return '$val .= \'\';'. "\n". - '$val .= SSViewer::parse_template('.$php.', $item);'. "\n". + '$val .= SSViewer::parse_template('.$php.', $scope->getItem());'. "\n". '$val .= \'\';'. "\n"; } else { return - '$val .= SSViewer::execute_template('.$php.', $item);'. "\n"; + '$val .= SSViewer::execute_template('.$php.', $scope->getItem());'. "\n"; } } @@ -1655,7 +1677,7 @@ class SSTemplateParser extends Parser { * This is an open block handler, for the <% debug %> utility tag */ function OpenBlock_Handle_Debug(&$res) { - if ($res['ArgumentCount'] == 0) return 'Debug::show($item);'; + if ($res['ArgumentCount'] == 0) return '$scope->debug();'; else if ($res['ArgumentCount'] == 1) { $arg = $res['Arguments'][0]; diff --git a/core/SSTemplateParser.php.inc b/core/SSTemplateParser.php.inc index 8c1abb4e9..2f9dbb14d 100644 --- a/core/SSTemplateParser.php.inc +++ b/core/SSTemplateParser.php.inc @@ -81,12 +81,6 @@ class SSTemplateParser extends Parser { */ protected $includeDebuggingComments = false; - function construct($name) { - $result = parent::construct($name); - $result['tags'] = array(); - return $result; - } - /*!* SSTemplateParser Word: / [A-Za-z_] [A-Za-z0-9_]* / @@ -107,7 +101,7 @@ class SSTemplateParser extends Parser { if (isset($res['php'])) $res['php'] .= ', '; else $res['php'] = ''; - $res['php'] .= ($sub['ArgumentMode'] == 'default') ? $sub['string_php'] : $sub['php']; + $res['php'] .= ($sub['ArgumentMode'] == 'default') ? $sub['string_php'] : str_replace('$$FINAL', 'XML_val', $sub['php']); } /*!* @@ -128,7 +122,7 @@ class SSTemplateParser extends Parser { */ function Lookup__construct(&$res) { - $res['php'] = '$item'; + $res['php'] = '$scope'; $res['LookupSteps'] = array(); } @@ -155,7 +149,7 @@ class SSTemplateParser extends Parser { } function Lookup_LastLookupStep(&$res, $sub) { - $this->Lookup_AddLookupStep($res, $sub, 'XML_val'); + $this->Lookup_AddLookupStep($res, $sub, '$$FINAL'); } /*!* @@ -168,7 +162,7 @@ class SSTemplateParser extends Parser { Injection: BracketInjection | SimpleInjection */ function Injection_STR(&$res, $sub) { - $res['php'] = '$val .= '. $sub['Lookup']['php'] . ';'; + $res['php'] = '$val .= '. str_replace('$$FINAL', 'XML_val', $sub['Lookup']['php']) . ';'; } /*!* @@ -261,11 +255,11 @@ class SSTemplateParser extends Parser { function Comparison_Argument(&$res, $sub) { if ($sub['ArgumentMode'] == 'default') { if (isset($res['php'])) $res['php'] .= $sub['string_php']; - else $res['php'] = $sub['lookup_php']; + else $res['php'] = str_replace('$$FINAL', 'XML_val', $sub['lookup_php']); } else { if (!isset($res['php'])) $res['php'] = ''; - $res['php'] .= $sub['php']; + $res['php'] .= str_replace('$$FINAL', 'XML_val', $sub['php']); } } @@ -289,7 +283,7 @@ class SSTemplateParser extends Parser { $php = ($sub['ArgumentMode'] == 'default' ? $sub['lookup_php'] : $sub['php']); // TODO: kinda hacky - maybe we need a way to pass state down the parse chain so // Lookup_LastLookupStep and Argument_BareWord can produce hasValue instead of XML_val - $res['php'] = str_replace('->XML_val', '->hasValue', $php); + $res['php'] = str_replace('$$FINAL', 'hasValue', $php); } } @@ -429,9 +423,9 @@ class SSTemplateParser extends Parser { } /** - * This is an example of a block handler function. This one handles the control tag. + * This is an example of a block handler function. This one handles the loop tag. */ - function ClosedBlock_Handle_Control(&$res) { + function ClosedBlock_Handle_Loop(&$res) { if ($res['ArgumentCount'] != 1) { throw new SSTemplateParseException('Either no or too many arguments in control block. Must be one argument only.', $this); } @@ -441,11 +435,39 @@ class SSTemplateParser extends Parser { throw new SSTemplateParseException('Control block cant take string as argument.', $this); } - $on = str_replace('->XML_val', '->obj', ($arg['ArgumentMode'] == 'default') ? $arg['lookup_php'] : $arg['php']); + $on = str_replace('$$FINAL', 'obj', ($arg['ArgumentMode'] == 'default') ? $arg['lookup_php'] : $arg['php']); return - 'array_push($itemStack, $item); if($loop = '.$on.') foreach($loop as $key => $item) {' . PHP_EOL . + $on . '; $scope->pushScope(); while (($key = $scope->next()) !== false) {' . PHP_EOL . $res['Template']['php'] . PHP_EOL . - '} $item = array_pop($itemStack); '; + '}; $scope->popScope(); '; + } + + /** + * The deprecated closed block handler for control blocks + * @deprecated + */ + function ClosedBlock_Handle_Control(&$res) { + return $this->ClosedBlock_Handle_Loop($res); + } + + /** + * The closed block handler for with blocks + */ + function ClosedBlock_Handle_With(&$res) { + if ($res['ArgumentCount'] != 1) { + throw new SSTemplateParseException('Either no or too many arguments in with block. Must be one argument only.', $this); + } + + $arg = $res['Arguments'][0]; + if ($arg['ArgumentMode'] == 'string') { + throw new SSTemplateParseException('Control block cant take string as argument.', $this); + } + + $on = str_replace('$$FINAL', 'obj', ($arg['ArgumentMode'] == 'default') ? $arg['lookup_php'] : $arg['php']); + return + $on . '; $scope->pushScope();' . PHP_EOL . + $res['Template']['php'] . PHP_EOL . + '; $scope->popScope(); '; } /*!* @@ -492,12 +514,12 @@ class SSTemplateParser extends Parser { if($this->includeDebuggingComments) { // Add include filename comments on dev sites return '$val .= \'\';'. "\n". - '$val .= SSViewer::parse_template('.$php.', $item);'. "\n". + '$val .= SSViewer::parse_template('.$php.', $scope->getItem());'. "\n". '$val .= \'\';'. "\n"; } else { return - '$val .= SSViewer::execute_template('.$php.', $item);'. "\n"; + '$val .= SSViewer::execute_template('.$php.', $scope->getItem());'. "\n"; } } @@ -505,7 +527,7 @@ class SSTemplateParser extends Parser { * This is an open block handler, for the <% debug %> utility tag */ function OpenBlock_Handle_Debug(&$res) { - if ($res['ArgumentCount'] == 0) return 'Debug::show($item);'; + if ($res['ArgumentCount'] == 0) return '$scope->debug();'; else if ($res['ArgumentCount'] == 1) { $arg = $res['Arguments'][0]; diff --git a/core/SSViewer.php b/core/SSViewer.php index 56dcbe00a..379e896bc 100755 --- a/core/SSViewer.php +++ b/core/SSViewer.php @@ -1,4 +1,129 @@ item = $item; + $this->localIndex=0; + $this->itemStack[] = array($this->item, null, null, null, 0); + } + + function getItem(){ + return $this->itemIterator ? $this->itemIterator->current() : $this->item; + } + + function resetLocalScope(){ + list($this->item, $this->itemIterator, $this->popIndex, $this->upIndex, $this->currentIndex) = $this->itemStack[$this->localIndex]; + array_splice($this->itemStack, $this->localIndex+1); + } + + function obj($name){ + + switch ($name) { + case 'Up': + list($this->item, $this->itemIterator, $unused2, $this->upIndex, $this->currentIndex) = $this->itemStack[$this->upIndex]; + break; + + case 'Top': + list($this->item, $this->itemIterator, $unused2, $this->upIndex, $this->currentIndex) = $this->itemStack[0]; + break; + + default: + $on = $this->itemIterator ? $this->itemIterator->current() : $this->item; + + $this->item = call_user_func_array(array($on, 'obj'), func_get_args()); + $this->itemIterator = null; + $this->upIndex = $this->currentIndex ? $this->currentIndex : count($this->itemStack)-1; + $this->currentIndex = count($this->itemStack); + break; + } + + $this->itemStack[] = array($this->item, $this->itemIterator, null, $this->upIndex, $this->currentIndex); + return $this; + } + + function pushScope(){ + $newLocalIndex = count($this->itemStack)-1; + + $this->popIndex = $this->itemStack[$newLocalIndex][2] = $this->localIndex; + $this->localIndex = $newLocalIndex; + + // We normally keep any previous itemIterator around, so local $Up calls reference the right element. But + // once we enter a new global scope, we need to make sure we use a new one + $this->itemIterator = $this->itemStack[$newLocalIndex][1] = null; + + return $this; + } + + function popScope(){ + $this->localIndex = $this->popIndex; + $this->resetLocalScope(); + + return $this; + } + + function next(){ + if (!$this->item) return false; + + if (!$this->itemIterator) { + if (is_array($this->item)) $this->itemIterator = new ArrayIterator($this->item); + else $this->itemIterator = $this->item->getIterator(); + + $this->itemStack[$this->localIndex][1] = $this->itemIterator; + $this->itemIterator->rewind(); + } + else { + $this->itemIterator->next(); + } + + $this->resetLocalScope(); + + if (!$this->itemIterator->valid()) return false; + return $this->itemIterator->key(); + } + + function __call($name, $arguments) { + $on = $this->itemIterator ? $this->itemIterator->current() : $this->item; + $retval = call_user_func_array(array($on, $name), $arguments); + + $this->resetLocalScope(); + return $retval; + } +} + /** * Parses a template file with an *.ss file extension. * @@ -422,14 +547,12 @@ class SSViewer { } } - $itemStack = array(); - $val = ""; - $valStack = array(); + $scope = new SSViewer_DataPresenter($item); + $val = ""; $valStack = array(); include($cacheFile); - $output = $val; - $output = Requirements::includeInHTML($template, $output); + $output = Requirements::includeInHTML($template, $val); array_pop(SSViewer::$topLevel); @@ -528,7 +651,7 @@ class SSViewer_FromString extends SSViewer { echo ""; } - $itemStack = array(); + $scope = new SSViewer_DataPresenter($item); $val = ""; $valStack = array(); diff --git a/tests/SSViewerTest.php b/tests/SSViewerTest.php index 61cd8cee3..874d50dd0 100644 --- a/tests/SSViewerTest.php +++ b/tests/SSViewerTest.php @@ -329,6 +329,137 @@ after') $this->assertEquals('A A1 A1 i A1 ii A2 A3', $rationalisedResult); } + + function assertEqualIgnoringWhitespace($a, $b) { + $this->assertEquals(preg_replace('/\s+/', '', $a), preg_replace('/\s+/', '', $b)); + } + + /** + * Test $Up works when the scope $Up refers to was entered with a "with" block + */ + function testUpInWith() { + + // Data to run the loop tests on - three levels deep + $data = new ArrayData(array( + 'Name' => 'Top', + 'Foo' => new ArrayData(array( + 'Name' => 'Foo', + 'Bar' => new ArrayData(array( + 'Name' => 'Bar', + 'Baz' => new ArrayData(array( + 'Name' => 'Baz' + )), + 'Qux' => new ArrayData(array( + 'Name' => 'Qux' + )) + )) + )) + )); + + // Basic functionality + $this->assertEquals('BarFoo', + $this->render('<% with Foo %><% with Bar %>{$Name}{$Up.Name}<% end_with %><% end_with %>', $data)); + + // Two level with block, up refers to internally referenced Bar + $this->assertEquals('BarFoo', + $this->render('<% with Foo.Bar %>{$Name}{$Up.Name}<% end_with %>', $data)); + + // Stepping up & back down the scope tree + $this->assertEquals('BazBarQux', + $this->render('<% with Foo.Bar.Baz %>{$Name}{$Up.Name}{$Up.Qux.Name}<% end_with %>', $data)); + + // Using $Up in a with block + $this->assertEquals('BazBarQux', + $this->render('<% with Foo.Bar.Baz %>{$Name}<% with $Up %>{$Name}{$Qux.Name}<% end_with %><% end_with %>', $data)); + + // Stepping up & back down the scope tree with with blocks + $this->assertEquals('BazBarQuxBarBaz', + $this->render('<% with Foo.Bar.Baz %>{$Name}<% with $Up %>{$Name}<% with Qux %>{$Name}<% end_with %>{$Name}<% end_with %>{$Name}<% end_with %>', $data)); + + // Using $Up.Up, where first $Up points to a previous scope entered using $Up, thereby skipping up to Foo + $this->assertEquals('Foo', + $this->render('<% with Foo.Bar.Baz %><% with Up %><% with Qux %>{$Up.Up.Name}<% end_with %><% end_with %><% end_with %>', $data)); + + // Using $Up.Up, where first $Up points to an Up used in a local scope lookup, should still skip to Foo + $this->assertEquals('Foo', + $this->render('<% with Foo.Bar.Baz.Up.Qux %>{$Up.Up.Name}<% end_with %>', $data)); + } + + /** + * Test $Up works when the scope $Up refers to was entered with a "loop" block + */ + function testUpInLoop(){ + + // Data to run the loop tests on - one sequence of three items, each with a subitem + $data = new ArrayData(array( + 'Name' => 'Top', + 'Foo' => new DataObjectSet(array( + new ArrayData(array( + 'Name' => '1', + 'Sub' => new ArrayData(array( + 'Name' => 'Bar' + )) + )), + new ArrayData(array( + 'Name' => '2', + 'Sub' => new ArrayData(array( + 'Name' => 'Baz' + )) + )), + new ArrayData(array( + 'Name' => '3', + 'Sub' => new ArrayData(array( + 'Name' => 'Qux' + )) + )) + )) + )); + + // Make sure inside a loop, $Up refers to the current item of the loop + $this->assertEqualIgnoringWhitespace( + '111 222 333', + $this->render( + '<% loop $Foo %>$Name<% with $Sub %>$Up.Name<% end_with %>$Name<% end_loop %>', + $data + ) + ); + + // Make sure inside a loop, looping over $Up uses a separate iterator, + // and doesn't interfere with the original iterator + $this->assertEqualIgnoringWhitespace( + '1Bar123Bar1 2Baz123Baz2 3Qux123Qux3', + $this->render( + '<% loop $Foo %> + $Name + <% with $Sub %> + $Name< + % loop $Up %>$Name<% end_loop %> + $Name + <% end_with %> + $Name + <% end_loop %>', + $data + ) + ); + + // Make sure inside a loop, looping over $Up uses a separate iterator, + // and doesn't interfere with the original iterator or local lookups + $this->assertEqualIgnoringWhitespace( + '1 Bar1 123 1Bar 1 2 Baz2 123 2Baz 2 3 Qux3 123 3Qux 3', + $this->render( + '<% loop $Foo %> + $Name + <% with $Sub %> + {$Name}{$Up.Name} + <% loop $Up %>$Name<% end_loop %> + {$Up.Name}{$Name} + <% end_with %> + $Name + <% end_loop %>', + $data + ) + ); + } } /** From 11459e40d404a491b9548f9ebdd5a6663a7a6e14 Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Mon, 21 Feb 2011 13:45:56 +1300 Subject: [PATCH 08/15] MINOR: Add instructions for how to compile parser to comment --- core/SSTemplateParser.php.inc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/SSTemplateParser.php.inc b/core/SSTemplateParser.php.inc index 2f9dbb14d..2d430320d 100644 --- a/core/SSTemplateParser.php.inc +++ b/core/SSTemplateParser.php.inc @@ -7,6 +7,10 @@ This is the uncompiled parser for the SilverStripe template language, PHP with s It gets run through the php-peg parser compiler to have those comments turned into code that match parts of the template language, producing the executable version SSTemplateParser.php +To recompile after changing this file, run this from the 'sapphire/core' directory via command line: + + php ../thirdparty/php-peg/cli.php SSTemplateParser.php.inc > SSTemplateParser.php + See the php-peg docs for more information on the parser format, and how to convert this file into SSTemplateParser.php TODO: From a34df1cb1f608b36c34c0ff976896d8a8341fb0e Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Mon, 21 Feb 2011 15:24:14 +1300 Subject: [PATCH 09/15] EHNANCEMENT: Allow presence checks in if and else_if blocks to be prefaced with not (allowed: <% if not A %>, not allowed: <% if not A == B %> - use <% if A != B %> instead --- core/SSTemplateParser.php | 1277 +++++++++++++++++---------------- core/SSTemplateParser.php.inc | 18 +- tests/SSViewerTest.php | 18 +- 3 files changed, 689 insertions(+), 624 deletions(-) diff --git a/core/SSTemplateParser.php b/core/SSTemplateParser.php index 0094a21eb..0cb40a392 100644 --- a/core/SSTemplateParser.php +++ b/core/SSTemplateParser.php @@ -783,62 +783,103 @@ class SSTemplateParser extends Parser { $res['php'] .= ($sub['text'] == '=' ? '==' : $sub['text']); } - /* PresenceCheck: Argument */ + /* PresenceCheck: (Not:'not' <)? Argument */ function match_PresenceCheck ($substack = array()) { $result = $this->construct( "PresenceCheck" ); - $key = "Argument"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); + $_115 = NULL; + do { + $res_113 = $result; + $pos_113 = $this->pos; + $_112 = NULL; + do { + $substack[] = $result; + $result = $this->construct( "Not" ); + $_108 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_108->expand('not') ) ) !== FALSE) { + $result["text"] .= $subres; + $subres = $result ; + $result = array_pop( $substack ) ; + $this->store( $result, $subres, 'Not' ); + } + else { + $result = array_pop( $substack ) ; + $_112 = FALSE; break; + } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_112 = TRUE; break; + } + while(0); + if( $_112 === FALSE) { + $result = $res_113; + $this->pos = $pos_113; + unset( $res_113 ); + unset( $pos_113 ); + } + $key = "Argument"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_115 = FALSE; break; } + $_115 = TRUE; break; + } + while(0); + if( $_115 === TRUE ) { return $this->finalise( "PresenceCheck", $result ); } - else { return FALSE; } + if( $_115 === FALSE) { return FALSE; } } + function PresenceCheck__construct(&$res) { + $res['php'] = ''; + } + + function PresenceCheck_Not(&$res, $sub) { + $res['php'] = '!'; + } + function PresenceCheck_Argument(&$res, $sub) { if ($sub['ArgumentMode'] == 'string') { - $res['php'] = '((bool)'.$sub['php'].')'; + $res['php'] .= '((bool)'.$sub['php'].')'; } else { $php = ($sub['ArgumentMode'] == 'default' ? $sub['lookup_php'] : $sub['php']); // TODO: kinda hacky - maybe we need a way to pass state down the parse chain so // Lookup_LastLookupStep and Argument_BareWord can produce hasValue instead of XML_val - $res['php'] = str_replace('$$FINAL', 'hasValue', $php); + $res['php'] .= str_replace('$$FINAL', 'hasValue', $php); } } /* IfArgumentPortion: Comparison | PresenceCheck */ function match_IfArgumentPortion ($substack = array()) { $result = $this->construct( "IfArgumentPortion" ); - $_112 = NULL; + $_120 = NULL; do { - $res_109 = $result; - $pos_109 = $this->pos; + $res_117 = $result; + $pos_117 = $this->pos; $key = "Comparison"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comparison(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_112 = TRUE; break; + $_120 = TRUE; break; } - $result = $res_109; - $this->pos = $pos_109; + $result = $res_117; + $this->pos = $pos_117; $key = "PresenceCheck"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_PresenceCheck(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_112 = TRUE; break; + $_120 = TRUE; break; } - $result = $res_109; - $this->pos = $pos_109; - $_112 = FALSE; break; + $result = $res_117; + $this->pos = $pos_117; + $_120 = FALSE; break; } while(0); - if( $_112 === TRUE ) { + if( $_120 === TRUE ) { return $this->finalise( "IfArgumentPortion", $result ); } - if( $_112 === FALSE) { return FALSE; } + if( $_120 === FALSE) { return FALSE; } } @@ -850,49 +891,49 @@ class SSTemplateParser extends Parser { /* BooleanOperator: "||" | "&&" */ function match_BooleanOperator ($substack = array()) { $result = $this->construct( "BooleanOperator" ); - $_119 = NULL; + $_127 = NULL; do { - $res_114 = $result; - $pos_114 = $this->pos; - $_115 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_115->expand("||") ) ) !== FALSE) { + $res_122 = $result; + $pos_122 = $this->pos; + $_123 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_123->expand("||") ) ) !== FALSE) { $result["text"] .= $subres; - $_119 = TRUE; break; + $_127 = TRUE; break; } - $result = $res_114; - $this->pos = $pos_114; - $_117 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_117->expand("&&") ) ) !== FALSE) { + $result = $res_122; + $this->pos = $pos_122; + $_125 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_125->expand("&&") ) ) !== FALSE) { $result["text"] .= $subres; - $_119 = TRUE; break; + $_127 = TRUE; break; } - $result = $res_114; - $this->pos = $pos_114; - $_119 = FALSE; break; + $result = $res_122; + $this->pos = $pos_122; + $_127 = FALSE; break; } while(0); - if( $_119 === TRUE ) { + if( $_127 === TRUE ) { return $this->finalise( "BooleanOperator", $result ); } - if( $_119 === FALSE) { return FALSE; } + if( $_127 === FALSE) { return FALSE; } } /* IfArgument: :IfArgumentPortion ( < :BooleanOperator < :IfArgumentPortion )* */ function match_IfArgument ($substack = array()) { $result = $this->construct( "IfArgument" ); - $_128 = NULL; + $_136 = NULL; do { $key = "IfArgumentPortion"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgumentPortion(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "IfArgumentPortion" ); } - else { $_128 = FALSE; break; } + else { $_136 = FALSE; break; } while (true) { - $res_127 = $result; - $pos_127 = $this->pos; - $_126 = NULL; + $res_135 = $result; + $pos_135 = $this->pos; + $_134 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $key = "BooleanOperator"; $pos = $this->pos; @@ -900,32 +941,32 @@ class SSTemplateParser extends Parser { if ($subres !== FALSE) { $this->store( $result, $subres, "BooleanOperator" ); } - else { $_126 = FALSE; break; } + else { $_134 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $key = "IfArgumentPortion"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgumentPortion(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "IfArgumentPortion" ); } - else { $_126 = FALSE; break; } - $_126 = TRUE; break; + else { $_134 = FALSE; break; } + $_134 = TRUE; break; } while(0); - if( $_126 === FALSE) { - $result = $res_127; - $this->pos = $pos_127; - unset( $res_127 ); - unset( $pos_127 ); + if( $_134 === FALSE) { + $result = $res_135; + $this->pos = $pos_135; + unset( $res_135 ); + unset( $pos_135 ); break; } } - $_128 = TRUE; break; + $_136 = TRUE; break; } while(0); - if( $_128 === TRUE ) { + if( $_136 === TRUE ) { return $this->finalise( "IfArgument", $result ); } - if( $_128 === FALSE) { return FALSE; } + if( $_136 === FALSE) { return FALSE; } } @@ -941,189 +982,191 @@ class SSTemplateParser extends Parser { $res['php'] .= $sub['text']; } - /* IfPart: '<%' < 'if' < :IfArgument > '%>' :Template? */ + /* IfPart: '<%' < 'if' [ :IfArgument > '%>' :Template? */ function match_IfPart ($substack = array()) { $result = $this->construct( "IfPart" ); - $_141 = NULL; + $_149 = NULL; do { - $_130 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_130->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_141 = FALSE; break; } + $_138 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_138->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_149 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_133 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_133->expand('if') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_141 = FALSE; break; } + $_141 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_141->expand('if') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_149 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_149 = FALSE; break; } $key = "IfArgument"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgument(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "IfArgument" ); } - else { $_141 = FALSE; break; } + else { $_149 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_138 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_138->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_141 = FALSE; break; } - $res_140 = $result; - $pos_140 = $this->pos; + $_146 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_146->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_149 = FALSE; break; } + $res_148 = $result; + $pos_148 = $this->pos; $key = "Template"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Template" ); } else { - $result = $res_140; - $this->pos = $pos_140; - unset( $res_140 ); - unset( $pos_140 ); + $result = $res_148; + $this->pos = $pos_148; + unset( $res_148 ); + unset( $pos_148 ); } - $_141 = TRUE; break; + $_149 = TRUE; break; } while(0); - if( $_141 === TRUE ) { + if( $_149 === TRUE ) { return $this->finalise( "IfPart", $result ); } - if( $_141 === FALSE) { return FALSE; } + if( $_149 === FALSE) { return FALSE; } } - /* ElseIfPart: '<%' < 'else_if' < :IfArgument > '%>' :Template? */ + /* ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' :Template? */ function match_ElseIfPart ($substack = array()) { $result = $this->construct( "ElseIfPart" ); - $_154 = NULL; + $_162 = NULL; do { - $_143 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_143->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_154 = FALSE; break; } + $_151 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_151->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_162 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_146 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_146->expand('else_if') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_154 = FALSE; break; } + $_154 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_154->expand('else_if') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_162 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_162 = FALSE; break; } $key = "IfArgument"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgument(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "IfArgument" ); } - else { $_154 = FALSE; break; } + else { $_162 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_151 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_151->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_154 = FALSE; break; } - $res_153 = $result; - $pos_153 = $this->pos; + $_159 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_159->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_162 = FALSE; break; } + $res_161 = $result; + $pos_161 = $this->pos; $key = "Template"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Template" ); } else { - $result = $res_153; - $this->pos = $pos_153; - unset( $res_153 ); - unset( $pos_153 ); + $result = $res_161; + $this->pos = $pos_161; + unset( $res_161 ); + unset( $pos_161 ); } - $_154 = TRUE; break; + $_162 = TRUE; break; } while(0); - if( $_154 === TRUE ) { + if( $_162 === TRUE ) { return $this->finalise( "ElseIfPart", $result ); } - if( $_154 === FALSE) { return FALSE; } + if( $_162 === FALSE) { return FALSE; } } /* ElsePart: '<%' < 'else' > '%>' :Template? */ function match_ElsePart ($substack = array()) { $result = $this->construct( "ElsePart" ); - $_165 = NULL; + $_173 = NULL; do { - $_156 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_156->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_165 = FALSE; break; } + $_164 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_164->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_173 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_159 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_159->expand('else') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_165 = FALSE; break; } + $_167 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_167->expand('else') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_173 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_162 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_162->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_165 = FALSE; break; } - $res_164 = $result; - $pos_164 = $this->pos; + $_170 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_170->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_173 = FALSE; break; } + $res_172 = $result; + $pos_172 = $this->pos; $key = "Template"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Template" ); } else { - $result = $res_164; - $this->pos = $pos_164; - unset( $res_164 ); - unset( $pos_164 ); + $result = $res_172; + $this->pos = $pos_172; + unset( $res_172 ); + unset( $pos_172 ); } - $_165 = TRUE; break; + $_173 = TRUE; break; } while(0); - if( $_165 === TRUE ) { + if( $_173 === TRUE ) { return $this->finalise( "ElsePart", $result ); } - if( $_165 === FALSE) { return FALSE; } + if( $_173 === FALSE) { return FALSE; } } /* If: IfPart ElseIfPart* ElsePart? '<%' < 'end_if' > '%>' */ function match_If ($substack = array()) { $result = $this->construct( "If" ); - $_178 = NULL; + $_186 = NULL; do { $key = "IfPart"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfPart(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_178 = FALSE; break; } + else { $_186 = FALSE; break; } while (true) { - $res_168 = $result; - $pos_168 = $this->pos; + $res_176 = $result; + $pos_176 = $this->pos; $key = "ElseIfPart"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ElseIfPart(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } else { - $result = $res_168; - $this->pos = $pos_168; - unset( $res_168 ); - unset( $pos_168 ); + $result = $res_176; + $this->pos = $pos_176; + unset( $res_176 ); + unset( $pos_176 ); break; } } - $res_169 = $result; - $pos_169 = $this->pos; + $res_177 = $result; + $pos_177 = $this->pos; $key = "ElsePart"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ElsePart(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } else { - $result = $res_169; - $this->pos = $pos_169; - unset( $res_169 ); - unset( $pos_169 ); + $result = $res_177; + $this->pos = $pos_177; + unset( $res_177 ); + unset( $pos_177 ); } - $_170 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_170->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_178 = FALSE; break; } + $_178 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_178->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_186 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_173 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_173->expand('end_if') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_178 = FALSE; break; } + $_181 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_181->expand('end_if') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_186 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_176 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_176->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_178 = FALSE; break; } - $_178 = TRUE; break; + $_184 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_184->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_186 = FALSE; break; } + $_186 = TRUE; break; } while(0); - if( $_178 === TRUE ) { + if( $_186 === TRUE ) { return $this->finalise( "If", $result ); } - if( $_178 === FALSE) { return FALSE; } + if( $_186 === FALSE) { return FALSE; } } @@ -1152,68 +1195,68 @@ class SSTemplateParser extends Parser { /* Require: '<%' < 'require' [ Call:(Method:Word "(" < :CallArguments > ")") > '%>' */ function match_Require ($substack = array()) { $result = $this->construct( "Require" ); - $_198 = NULL; + $_206 = NULL; do { - $_180 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_180->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_198 = FALSE; break; } + $_188 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_188->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_206 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_183 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_183->expand('require') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_198 = FALSE; break; } + $_191 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_191->expand('require') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_206 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_198 = FALSE; break; } + else { $_206 = FALSE; break; } $substack[] = $result; $result = $this->construct( "Call" ); - $_192 = NULL; + $_200 = NULL; do { $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Method" ); } - else { $_192 = FALSE; break; } + else { $_200 = FALSE; break; } if (substr($this->string,$this->pos,1) == "(") { $this->pos += 1; $result["text"] .= "("; } - else { $_192 = FALSE; break; } + else { $_200 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $key = "CallArguments"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_CallArguments(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "CallArguments" ); } - else { $_192 = FALSE; break; } + else { $_200 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } if (substr($this->string,$this->pos,1) == ")") { $this->pos += 1; $result["text"] .= ")"; } - else { $_192 = FALSE; break; } - $_192 = TRUE; break; + else { $_200 = FALSE; break; } + $_200 = TRUE; break; } while(0); - if( $_192 === TRUE ) { + if( $_200 === TRUE ) { $subres = $result ; $result = array_pop( $substack ) ; $this->store( $result, $subres, 'Call' ); } - if( $_192 === FALSE) { + if( $_200 === FALSE) { $result = array_pop( $substack ) ; - $_198 = FALSE; break; + $_206 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_196 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_196->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_198 = FALSE; break; } - $_198 = TRUE; break; + $_204 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_204->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_206 = FALSE; break; } + $_206 = TRUE; break; } while(0); - if( $_198 === TRUE ) { + if( $_206 === TRUE ) { return $this->finalise( "Require", $result ); } - if( $_198 === FALSE) { return FALSE; } + if( $_206 === FALSE) { return FALSE; } } @@ -1225,206 +1268,206 @@ class SSTemplateParser extends Parser { /* BlockArguments: :Argument ( < "," < :Argument)* */ function match_BlockArguments ($substack = array()) { $result = $this->construct( "BlockArguments" ); - $_207 = NULL; + $_215 = NULL; do { $key = "Argument"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Argument" ); } - else { $_207 = FALSE; break; } + else { $_215 = FALSE; break; } while (true) { - $res_206 = $result; - $pos_206 = $this->pos; - $_205 = NULL; + $res_214 = $result; + $pos_214 = $this->pos; + $_213 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } if (substr($this->string,$this->pos,1) == ",") { $this->pos += 1; $result["text"] .= ","; } - else { $_205 = FALSE; break; } + else { $_213 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $key = "Argument"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Argument" ); } - else { $_205 = FALSE; break; } - $_205 = TRUE; break; + else { $_213 = FALSE; break; } + $_213 = TRUE; break; } while(0); - if( $_205 === FALSE) { - $result = $res_206; - $this->pos = $pos_206; - unset( $res_206 ); - unset( $pos_206 ); + if( $_213 === FALSE) { + $result = $res_214; + $this->pos = $pos_214; + unset( $res_214 ); + unset( $pos_214 ); break; } } - $_207 = TRUE; break; + $_215 = TRUE; break; } while(0); - if( $_207 === TRUE ) { + if( $_215 === TRUE ) { return $this->finalise( "BlockArguments", $result ); } - if( $_207 === FALSE) { return FALSE; } + if( $_215 === FALSE) { return FALSE; } } /* NotBlockTag: "end_" | (("if" | "else_if" | "else" | "require") ] ) */ function match_NotBlockTag ($substack = array()) { $result = $this->construct( "NotBlockTag" ); - $_234 = NULL; + $_242 = NULL; do { - $res_209 = $result; - $pos_209 = $this->pos; - $_210 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_210->expand("end_") ) ) !== FALSE) { + $res_217 = $result; + $pos_217 = $this->pos; + $_218 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_218->expand("end_") ) ) !== FALSE) { $result["text"] .= $subres; - $_234 = TRUE; break; + $_242 = TRUE; break; } - $result = $res_209; - $this->pos = $pos_209; - $_232 = NULL; + $result = $res_217; + $this->pos = $pos_217; + $_240 = NULL; do { - $_229 = NULL; + $_237 = NULL; do { - $_227 = NULL; + $_235 = NULL; do { - $res_212 = $result; - $pos_212 = $this->pos; - $_213 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_213->expand("if") ) ) !== FALSE) { + $res_220 = $result; + $pos_220 = $this->pos; + $_221 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_221->expand("if") ) ) !== FALSE) { $result["text"] .= $subres; - $_227 = TRUE; break; + $_235 = TRUE; break; } - $result = $res_212; - $this->pos = $pos_212; - $_225 = NULL; + $result = $res_220; + $this->pos = $pos_220; + $_233 = NULL; do { - $res_215 = $result; - $pos_215 = $this->pos; - $_216 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_216->expand("else_if") ) ) !== FALSE) { + $res_223 = $result; + $pos_223 = $this->pos; + $_224 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_224->expand("else_if") ) ) !== FALSE) { $result["text"] .= $subres; - $_225 = TRUE; break; + $_233 = TRUE; break; } - $result = $res_215; - $this->pos = $pos_215; - $_223 = NULL; + $result = $res_223; + $this->pos = $pos_223; + $_231 = NULL; do { - $res_218 = $result; - $pos_218 = $this->pos; - $_219 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_219->expand("else") ) ) !== FALSE) { + $res_226 = $result; + $pos_226 = $this->pos; + $_227 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_227->expand("else") ) ) !== FALSE) { $result["text"] .= $subres; - $_223 = TRUE; break; + $_231 = TRUE; break; } - $result = $res_218; - $this->pos = $pos_218; - $_221 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_221->expand("require") ) ) !== FALSE) { + $result = $res_226; + $this->pos = $pos_226; + $_229 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_229->expand("require") ) ) !== FALSE) { $result["text"] .= $subres; - $_223 = TRUE; break; + $_231 = TRUE; break; } - $result = $res_218; - $this->pos = $pos_218; - $_223 = FALSE; break; + $result = $res_226; + $this->pos = $pos_226; + $_231 = FALSE; break; } while(0); - if( $_223 === TRUE ) { $_225 = TRUE; break; } - $result = $res_215; - $this->pos = $pos_215; - $_225 = FALSE; break; + if( $_231 === TRUE ) { $_233 = TRUE; break; } + $result = $res_223; + $this->pos = $pos_223; + $_233 = FALSE; break; } while(0); - if( $_225 === TRUE ) { $_227 = TRUE; break; } - $result = $res_212; - $this->pos = $pos_212; - $_227 = FALSE; break; + if( $_233 === TRUE ) { $_235 = TRUE; break; } + $result = $res_220; + $this->pos = $pos_220; + $_235 = FALSE; break; } while(0); - if( $_227 === FALSE) { $_229 = FALSE; break; } - $_229 = TRUE; break; + if( $_235 === FALSE) { $_237 = FALSE; break; } + $_237 = TRUE; break; } while(0); - if( $_229 === FALSE) { $_232 = FALSE; break; } + if( $_237 === FALSE) { $_240 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_232 = FALSE; break; } - $_232 = TRUE; break; + else { $_240 = FALSE; break; } + $_240 = TRUE; break; } while(0); - if( $_232 === TRUE ) { $_234 = TRUE; break; } - $result = $res_209; - $this->pos = $pos_209; - $_234 = FALSE; break; + if( $_240 === TRUE ) { $_242 = TRUE; break; } + $result = $res_217; + $this->pos = $pos_217; + $_242 = FALSE; break; } while(0); - if( $_234 === TRUE ) { + if( $_242 === TRUE ) { return $this->finalise( "NotBlockTag", $result ); } - if( $_234 === FALSE) { return FALSE; } + if( $_242 === FALSE) { return FALSE; } } /* ClosedBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > Zap:'%>' :Template? '<%' < 'end_' '$BlockName' > '%>' */ function match_ClosedBlock ($substack = array()) { $result = $this->construct( "ClosedBlock" ); - $_261 = NULL; + $_269 = NULL; do { - $_236 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_236->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_261 = FALSE; break; } + $_244 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_244->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_269 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_239 = $result; - $pos_239 = $this->pos; + $res_247 = $result; + $pos_247 = $this->pos; $key = "NotBlockTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $result = $res_239; - $this->pos = $pos_239; - $_261 = FALSE; break; + $result = $res_247; + $this->pos = $pos_247; + $_269 = FALSE; break; } else { - $result = $res_239; - $this->pos = $pos_239; + $result = $res_247; + $this->pos = $pos_247; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockName" ); } - else { $_261 = FALSE; break; } - $res_245 = $result; - $pos_245 = $this->pos; - $_244 = NULL; + else { $_269 = FALSE; break; } + $res_253 = $result; + $pos_253 = $this->pos; + $_252 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_244 = FALSE; break; } + else { $_252 = FALSE; break; } $key = "BlockArguments"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockArguments" ); } - else { $_244 = FALSE; break; } + else { $_252 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_244 = FALSE; break; } - $_244 = TRUE; break; + else { $_252 = FALSE; break; } + $_252 = TRUE; break; } while(0); - if( $_244 === FALSE) { - $result = $res_245; - $this->pos = $pos_245; - unset( $res_245 ); - unset( $pos_245 ); + if( $_252 === FALSE) { + $result = $res_253; + $this->pos = $pos_253; + unset( $res_253 ); + unset( $pos_253 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $substack[] = $result; $result = $this->construct( "Zap" ); - $_247 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_247->expand('%>') ) ) !== FALSE) { + $_255 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_255->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; $subres = $result ; $result = array_pop( $substack ) ; @@ -1432,42 +1475,42 @@ class SSTemplateParser extends Parser { } else { $result = array_pop( $substack ) ; - $_261 = FALSE; break; + $_269 = FALSE; break; } - $res_250 = $result; - $pos_250 = $this->pos; + $res_258 = $result; + $pos_258 = $this->pos; $key = "Template"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Template" ); } else { - $result = $res_250; - $this->pos = $pos_250; - unset( $res_250 ); - unset( $pos_250 ); + $result = $res_258; + $this->pos = $pos_258; + unset( $res_258 ); + unset( $pos_258 ); } - $_251 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_251->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_261 = FALSE; break; } - if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_254 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_254->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_261 = FALSE; break; } - $_256 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_256->expand('$BlockName') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_261 = FALSE; break; } - if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $_259 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_259->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_261 = FALSE; break; } - $_261 = TRUE; break; + if (( $subres = $this->literal( $_259->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_269 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_262 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_262->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_269 = FALSE; break; } + $_264 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_264->expand('$BlockName') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_269 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_267 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_267->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_269 = FALSE; break; } + $_269 = TRUE; break; } while(0); - if( $_261 === TRUE ) { + if( $_269 === TRUE ) { return $this->finalise( "ClosedBlock", $result ); } - if( $_261 === FALSE) { return FALSE; } + if( $_269 === FALSE) { return FALSE; } } @@ -1563,66 +1606,66 @@ class SSTemplateParser extends Parser { /* OpenBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > '%>' */ function match_OpenBlock ($substack = array()) { $result = $this->construct( "OpenBlock" ); - $_276 = NULL; + $_284 = NULL; do { - $_263 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_263->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_276 = FALSE; break; } + $_271 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_271->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_284 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_266 = $result; - $pos_266 = $this->pos; + $res_274 = $result; + $pos_274 = $this->pos; $key = "NotBlockTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $result = $res_266; - $this->pos = $pos_266; - $_276 = FALSE; break; + $result = $res_274; + $this->pos = $pos_274; + $_284 = FALSE; break; } else { - $result = $res_266; - $this->pos = $pos_266; + $result = $res_274; + $this->pos = $pos_274; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockName" ); } - else { $_276 = FALSE; break; } - $res_272 = $result; - $pos_272 = $this->pos; - $_271 = NULL; + else { $_284 = FALSE; break; } + $res_280 = $result; + $pos_280 = $this->pos; + $_279 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_271 = FALSE; break; } + else { $_279 = FALSE; break; } $key = "BlockArguments"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockArguments" ); } - else { $_271 = FALSE; break; } + else { $_279 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_271 = FALSE; break; } - $_271 = TRUE; break; + else { $_279 = FALSE; break; } + $_279 = TRUE; break; } while(0); - if( $_271 === FALSE) { - $result = $res_272; - $this->pos = $pos_272; - unset( $res_272 ); - unset( $pos_272 ); + if( $_279 === FALSE) { + $result = $res_280; + $this->pos = $pos_280; + unset( $res_280 ); + unset( $pos_280 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_274 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_274->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_276 = FALSE; break; } - $_276 = TRUE; break; + $_282 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_282->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_284 = FALSE; break; } + $_284 = TRUE; break; } while(0); - if( $_276 === TRUE ) { + if( $_284 === TRUE ) { return $this->finalise( "OpenBlock", $result ); } - if( $_276 === FALSE) { return FALSE; } + if( $_284 === FALSE) { return FALSE; } } @@ -1710,30 +1753,30 @@ class SSTemplateParser extends Parser { /* MismatchedEndBlock: '<%' < 'end_' Word > '%>' */ function match_MismatchedEndBlock ($substack = array()) { $result = $this->construct( "MismatchedEndBlock" ); - $_287 = NULL; + $_295 = NULL; do { - $_278 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_278->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_287 = FALSE; break; } + $_286 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_286->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_295 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_281 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_281->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_287 = FALSE; break; } + $_289 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_289->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_295 = FALSE; break; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_287 = FALSE; break; } + else { $_295 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_285 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_285->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_287 = FALSE; break; } - $_287 = TRUE; break; + $_293 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_293->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_295 = FALSE; break; } + $_295 = TRUE; break; } while(0); - if( $_287 === TRUE ) { + if( $_295 === TRUE ) { return $this->finalise( "MismatchedEndBlock", $result ); } - if( $_287 === FALSE) { return FALSE; } + if( $_295 === FALSE) { return FALSE; } } @@ -1746,82 +1789,82 @@ class SSTemplateParser extends Parser { /* MalformedOpenTag: '<%' < !NotBlockTag Tag:Word !( ( [ :BlockArguments ] )? > '%>' ) */ function match_MalformedOpenTag ($substack = array()) { $result = $this->construct( "MalformedOpenTag" ); - $_304 = NULL; + $_312 = NULL; do { - $_289 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_289->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_304 = FALSE; break; } + $_297 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_297->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_312 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_292 = $result; - $pos_292 = $this->pos; + $res_300 = $result; + $pos_300 = $this->pos; $key = "NotBlockTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $result = $res_292; - $this->pos = $pos_292; - $_304 = FALSE; break; + $result = $res_300; + $this->pos = $pos_300; + $_312 = FALSE; break; } else { - $result = $res_292; - $this->pos = $pos_292; + $result = $res_300; + $this->pos = $pos_300; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Tag" ); } - else { $_304 = FALSE; break; } - $res_303 = $result; - $pos_303 = $this->pos; - $_302 = NULL; + else { $_312 = FALSE; break; } + $res_311 = $result; + $pos_311 = $this->pos; + $_310 = NULL; do { - $res_298 = $result; - $pos_298 = $this->pos; - $_297 = NULL; + $res_306 = $result; + $pos_306 = $this->pos; + $_305 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_297 = FALSE; break; } + else { $_305 = FALSE; break; } $key = "BlockArguments"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockArguments" ); } - else { $_297 = FALSE; break; } + else { $_305 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_297 = FALSE; break; } - $_297 = TRUE; break; + else { $_305 = FALSE; break; } + $_305 = TRUE; break; } while(0); - if( $_297 === FALSE) { - $result = $res_298; - $this->pos = $pos_298; - unset( $res_298 ); - unset( $pos_298 ); + if( $_305 === FALSE) { + $result = $res_306; + $this->pos = $pos_306; + unset( $res_306 ); + unset( $pos_306 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_300 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_300->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_302 = FALSE; break; } - $_302 = TRUE; break; + $_308 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_308->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_310 = FALSE; break; } + $_310 = TRUE; break; } while(0); - if( $_302 === TRUE ) { - $result = $res_303; - $this->pos = $pos_303; - $_304 = FALSE; break; + if( $_310 === TRUE ) { + $result = $res_311; + $this->pos = $pos_311; + $_312 = FALSE; break; } - if( $_302 === FALSE) { - $result = $res_303; - $this->pos = $pos_303; + if( $_310 === FALSE) { + $result = $res_311; + $this->pos = $pos_311; } - $_304 = TRUE; break; + $_312 = TRUE; break; } while(0); - if( $_304 === TRUE ) { + if( $_312 === TRUE ) { return $this->finalise( "MalformedOpenTag", $result ); } - if( $_304 === FALSE) { return FALSE; } + if( $_312 === FALSE) { return FALSE; } } @@ -1834,64 +1877,64 @@ class SSTemplateParser extends Parser { /* MalformedCloseTag: '<%' < Tag:('end_' :Word ) !( > '%>' ) */ function match_MalformedCloseTag ($substack = array()) { $result = $this->construct( "MalformedCloseTag" ); - $_320 = NULL; + $_328 = NULL; do { - $_306 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_306->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_320 = FALSE; break; } + $_314 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_314->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_328 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $substack[] = $result; $result = $this->construct( "Tag" ); - $_312 = NULL; + $_320 = NULL; do { - $_309 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_309->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_312 = FALSE; break; } + $_317 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_317->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_320 = FALSE; break; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Word" ); } - else { $_312 = FALSE; break; } - $_312 = TRUE; break; + else { $_320 = FALSE; break; } + $_320 = TRUE; break; } while(0); - if( $_312 === TRUE ) { + if( $_320 === TRUE ) { $subres = $result ; $result = array_pop( $substack ) ; $this->store( $result, $subres, 'Tag' ); } - if( $_312 === FALSE) { + if( $_320 === FALSE) { $result = array_pop( $substack ) ; - $_320 = FALSE; break; + $_328 = FALSE; break; } - $res_319 = $result; - $pos_319 = $this->pos; - $_318 = NULL; + $res_327 = $result; + $pos_327 = $this->pos; + $_326 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_316 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_316->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_318 = FALSE; break; } - $_318 = TRUE; break; + $_324 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_324->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_326 = FALSE; break; } + $_326 = TRUE; break; } while(0); - if( $_318 === TRUE ) { - $result = $res_319; - $this->pos = $pos_319; - $_320 = FALSE; break; + if( $_326 === TRUE ) { + $result = $res_327; + $this->pos = $pos_327; + $_328 = FALSE; break; } - if( $_318 === FALSE) { - $result = $res_319; - $this->pos = $pos_319; + if( $_326 === FALSE) { + $result = $res_327; + $this->pos = $pos_327; } - $_320 = TRUE; break; + $_328 = TRUE; break; } while(0); - if( $_320 === TRUE ) { + if( $_328 === TRUE ) { return $this->finalise( "MalformedCloseTag", $result ); } - if( $_320 === FALSE) { return FALSE; } + if( $_328 === FALSE) { return FALSE; } } @@ -1904,33 +1947,33 @@ class SSTemplateParser extends Parser { /* MalformedBlock: MalformedOpenTag | MalformedCloseTag */ function match_MalformedBlock ($substack = array()) { $result = $this->construct( "MalformedBlock" ); - $_325 = NULL; + $_333 = NULL; do { - $res_322 = $result; - $pos_322 = $this->pos; + $res_330 = $result; + $pos_330 = $this->pos; $key = "MalformedOpenTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedOpenTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_325 = TRUE; break; + $_333 = TRUE; break; } - $result = $res_322; - $this->pos = $pos_322; + $result = $res_330; + $this->pos = $pos_330; $key = "MalformedCloseTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedCloseTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_325 = TRUE; break; + $_333 = TRUE; break; } - $result = $res_322; - $this->pos = $pos_322; - $_325 = FALSE; break; + $result = $res_330; + $this->pos = $pos_330; + $_333 = FALSE; break; } while(0); - if( $_325 === TRUE ) { + if( $_333 === TRUE ) { return $this->finalise( "MalformedBlock", $result ); } - if( $_325 === FALSE) { return FALSE; } + if( $_333 === FALSE) { return FALSE; } } @@ -1939,57 +1982,57 @@ class SSTemplateParser extends Parser { /* Comment: "<%--" (!"--%>" /./)+ "--%>" */ function match_Comment ($substack = array()) { $result = $this->construct( "Comment" ); - $_337 = NULL; + $_345 = NULL; do { - $_327 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_327->expand("<%--") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_337 = FALSE; break; } + $_335 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_335->expand("<%--") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_345 = FALSE; break; } $count = 0; while (true) { - $res_334 = $result; - $pos_334 = $this->pos; - $_333 = NULL; + $res_342 = $result; + $pos_342 = $this->pos; + $_341 = NULL; do { - $res_330 = $result; - $pos_330 = $this->pos; - $_329 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_329->expand("--%>") ) ) !== FALSE) { + $res_338 = $result; + $pos_338 = $this->pos; + $_337 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_337->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; - $result = $res_330; - $this->pos = $pos_330; - $_333 = FALSE; break; + $result = $res_338; + $this->pos = $pos_338; + $_341 = FALSE; break; } else { - $result = $res_330; - $this->pos = $pos_330; + $result = $res_338; + $this->pos = $pos_338; } - $_331 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_331->expand('/./') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_333 = FALSE; break; } - $_333 = TRUE; break; + $_339 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_339->expand('/./') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_341 = FALSE; break; } + $_341 = TRUE; break; } while(0); - if( $_333 === FALSE) { - $result = $res_334; - $this->pos = $pos_334; - unset( $res_334 ); - unset( $pos_334 ); + if( $_341 === FALSE) { + $result = $res_342; + $this->pos = $pos_342; + unset( $res_342 ); + unset( $pos_342 ); break; } $count += 1; } if ($count > 0) { } - else { $_337 = FALSE; break; } - $_335 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_335->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_337 = FALSE; break; } - $_337 = TRUE; break; + else { $_345 = FALSE; break; } + $_343 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_343->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_345 = FALSE; break; } + $_345 = TRUE; break; } while(0); - if( $_337 === TRUE ) { + if( $_345 === TRUE ) { return $this->finalise( "Comment", $result ); } - if( $_337 === FALSE) { return FALSE; } + if( $_345 === FALSE) { return FALSE; } } @@ -2010,8 +2053,8 @@ class SSTemplateParser extends Parser { / */ function match_Text ($substack = array()) { $result = array("name"=>"Text", "text"=>""); - $_339 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_339->expand('/ + $_347 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_347->expand('/ ( (\\\\.) | # Any escaped character ([^<${]) | # Any character that isn\'t <, $ or { @@ -2033,150 +2076,150 @@ class SSTemplateParser extends Parser { $result = $this->construct( "Template" ); $count = 0; while (true) { - $res_371 = $result; - $pos_371 = $this->pos; - $_370 = NULL; + $res_379 = $result; + $pos_379 = $this->pos; + $_378 = NULL; do { - $_368 = NULL; + $_376 = NULL; do { - $res_341 = $result; - $pos_341 = $this->pos; + $res_349 = $result; + $pos_349 = $this->pos; $key = "Comment"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comment(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_368 = TRUE; break; + $_376 = TRUE; break; } - $result = $res_341; - $this->pos = $pos_341; - $_366 = NULL; + $result = $res_349; + $this->pos = $pos_349; + $_374 = NULL; do { - $res_343 = $result; - $pos_343 = $this->pos; + $res_351 = $result; + $pos_351 = $this->pos; $key = "If"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_If(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_366 = TRUE; break; + $_374 = TRUE; break; } - $result = $res_343; - $this->pos = $pos_343; - $_364 = NULL; + $result = $res_351; + $this->pos = $pos_351; + $_372 = NULL; do { - $res_345 = $result; - $pos_345 = $this->pos; + $res_353 = $result; + $pos_353 = $this->pos; $key = "Require"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Require(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_364 = TRUE; break; + $_372 = TRUE; break; } - $result = $res_345; - $this->pos = $pos_345; - $_362 = NULL; + $result = $res_353; + $this->pos = $pos_353; + $_370 = NULL; do { - $res_347 = $result; - $pos_347 = $this->pos; + $res_355 = $result; + $pos_355 = $this->pos; $key = "ClosedBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_362 = TRUE; break; + $_370 = TRUE; break; } - $result = $res_347; - $this->pos = $pos_347; - $_360 = NULL; + $result = $res_355; + $this->pos = $pos_355; + $_368 = NULL; do { - $res_349 = $result; - $pos_349 = $this->pos; + $res_357 = $result; + $pos_357 = $this->pos; $key = "OpenBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_360 = TRUE; break; + $_368 = TRUE; break; } - $result = $res_349; - $this->pos = $pos_349; - $_358 = NULL; + $result = $res_357; + $this->pos = $pos_357; + $_366 = NULL; do { - $res_351 = $result; - $pos_351 = $this->pos; + $res_359 = $result; + $pos_359 = $this->pos; $key = "MalformedBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_358 = TRUE; break; + $_366 = TRUE; break; } - $result = $res_351; - $this->pos = $pos_351; - $_356 = NULL; + $result = $res_359; + $this->pos = $pos_359; + $_364 = NULL; do { - $res_353 = $result; - $pos_353 = $this->pos; + $res_361 = $result; + $pos_361 = $this->pos; $key = "Injection"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_356 = TRUE; break; + $_364 = TRUE; break; } - $result = $res_353; - $this->pos = $pos_353; + $result = $res_361; + $this->pos = $pos_361; $key = "Text"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_356 = TRUE; break; + $_364 = TRUE; break; } - $result = $res_353; - $this->pos = $pos_353; - $_356 = FALSE; break; + $result = $res_361; + $this->pos = $pos_361; + $_364 = FALSE; break; } while(0); - if( $_356 === TRUE ) { $_358 = TRUE; break; } - $result = $res_351; - $this->pos = $pos_351; - $_358 = FALSE; break; + if( $_364 === TRUE ) { $_366 = TRUE; break; } + $result = $res_359; + $this->pos = $pos_359; + $_366 = FALSE; break; } while(0); - if( $_358 === TRUE ) { $_360 = TRUE; break; } - $result = $res_349; - $this->pos = $pos_349; - $_360 = FALSE; break; + if( $_366 === TRUE ) { $_368 = TRUE; break; } + $result = $res_357; + $this->pos = $pos_357; + $_368 = FALSE; break; } while(0); - if( $_360 === TRUE ) { $_362 = TRUE; break; } - $result = $res_347; - $this->pos = $pos_347; - $_362 = FALSE; break; + if( $_368 === TRUE ) { $_370 = TRUE; break; } + $result = $res_355; + $this->pos = $pos_355; + $_370 = FALSE; break; } while(0); - if( $_362 === TRUE ) { $_364 = TRUE; break; } - $result = $res_345; - $this->pos = $pos_345; - $_364 = FALSE; break; + if( $_370 === TRUE ) { $_372 = TRUE; break; } + $result = $res_353; + $this->pos = $pos_353; + $_372 = FALSE; break; } while(0); - if( $_364 === TRUE ) { $_366 = TRUE; break; } - $result = $res_343; - $this->pos = $pos_343; - $_366 = FALSE; break; + if( $_372 === TRUE ) { $_374 = TRUE; break; } + $result = $res_351; + $this->pos = $pos_351; + $_374 = FALSE; break; } while(0); - if( $_366 === TRUE ) { $_368 = TRUE; break; } - $result = $res_341; - $this->pos = $pos_341; - $_368 = FALSE; break; + if( $_374 === TRUE ) { $_376 = TRUE; break; } + $result = $res_349; + $this->pos = $pos_349; + $_376 = FALSE; break; } while(0); - if( $_368 === FALSE) { $_370 = FALSE; break; } - $_370 = TRUE; break; + if( $_376 === FALSE) { $_378 = FALSE; break; } + $_378 = TRUE; break; } while(0); - if( $_370 === FALSE) { - $result = $res_371; - $this->pos = $pos_371; - unset( $res_371 ); - unset( $pos_371 ); + if( $_378 === FALSE) { + $result = $res_379; + $this->pos = $pos_379; + unset( $res_379 ); + unset( $pos_379 ); break; } $count += 1; @@ -2219,168 +2262,168 @@ class SSTemplateParser extends Parser { $result = $this->construct( "TopTemplate" ); $count = 0; while (true) { - $res_406 = $result; - $pos_406 = $this->pos; - $_405 = NULL; + $res_414 = $result; + $pos_414 = $this->pos; + $_413 = NULL; do { - $_403 = NULL; + $_411 = NULL; do { - $res_372 = $result; - $pos_372 = $this->pos; + $res_380 = $result; + $pos_380 = $this->pos; $key = "Comment"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comment(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_403 = TRUE; break; + $_411 = TRUE; break; } - $result = $res_372; - $this->pos = $pos_372; - $_401 = NULL; + $result = $res_380; + $this->pos = $pos_380; + $_409 = NULL; do { - $res_374 = $result; - $pos_374 = $this->pos; + $res_382 = $result; + $pos_382 = $this->pos; $key = "If"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_If(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_401 = TRUE; break; + $_409 = TRUE; break; } - $result = $res_374; - $this->pos = $pos_374; - $_399 = NULL; + $result = $res_382; + $this->pos = $pos_382; + $_407 = NULL; do { - $res_376 = $result; - $pos_376 = $this->pos; + $res_384 = $result; + $pos_384 = $this->pos; $key = "Require"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Require(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_399 = TRUE; break; + $_407 = TRUE; break; } - $result = $res_376; - $this->pos = $pos_376; - $_397 = NULL; + $result = $res_384; + $this->pos = $pos_384; + $_405 = NULL; do { - $res_378 = $result; - $pos_378 = $this->pos; + $res_386 = $result; + $pos_386 = $this->pos; $key = "ClosedBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_397 = TRUE; break; + $_405 = TRUE; break; } - $result = $res_378; - $this->pos = $pos_378; - $_395 = NULL; + $result = $res_386; + $this->pos = $pos_386; + $_403 = NULL; do { - $res_380 = $result; - $pos_380 = $this->pos; + $res_388 = $result; + $pos_388 = $this->pos; $key = "OpenBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_395 = TRUE; break; + $_403 = TRUE; break; } - $result = $res_380; - $this->pos = $pos_380; - $_393 = NULL; + $result = $res_388; + $this->pos = $pos_388; + $_401 = NULL; do { - $res_382 = $result; - $pos_382 = $this->pos; + $res_390 = $result; + $pos_390 = $this->pos; $key = "MalformedBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_393 = TRUE; break; + $_401 = TRUE; break; } - $result = $res_382; - $this->pos = $pos_382; - $_391 = NULL; + $result = $res_390; + $this->pos = $pos_390; + $_399 = NULL; do { - $res_384 = $result; - $pos_384 = $this->pos; + $res_392 = $result; + $pos_392 = $this->pos; $key = "MismatchedEndBlock"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MismatchedEndBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_391 = TRUE; break; + $_399 = TRUE; break; } - $result = $res_384; - $this->pos = $pos_384; - $_389 = NULL; + $result = $res_392; + $this->pos = $pos_392; + $_397 = NULL; do { - $res_386 = $result; - $pos_386 = $this->pos; + $res_394 = $result; + $pos_394 = $this->pos; $key = "Injection"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_389 = TRUE; break; + $_397 = TRUE; break; } - $result = $res_386; - $this->pos = $pos_386; + $result = $res_394; + $this->pos = $pos_394; $key = "Text"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_389 = TRUE; break; + $_397 = TRUE; break; } - $result = $res_386; - $this->pos = $pos_386; - $_389 = FALSE; break; + $result = $res_394; + $this->pos = $pos_394; + $_397 = FALSE; break; } while(0); - if( $_389 === TRUE ) { $_391 = TRUE; break; } - $result = $res_384; - $this->pos = $pos_384; - $_391 = FALSE; break; + if( $_397 === TRUE ) { $_399 = TRUE; break; } + $result = $res_392; + $this->pos = $pos_392; + $_399 = FALSE; break; } while(0); - if( $_391 === TRUE ) { $_393 = TRUE; break; } - $result = $res_382; - $this->pos = $pos_382; - $_393 = FALSE; break; + if( $_399 === TRUE ) { $_401 = TRUE; break; } + $result = $res_390; + $this->pos = $pos_390; + $_401 = FALSE; break; } while(0); - if( $_393 === TRUE ) { $_395 = TRUE; break; } - $result = $res_380; - $this->pos = $pos_380; - $_395 = FALSE; break; + if( $_401 === TRUE ) { $_403 = TRUE; break; } + $result = $res_388; + $this->pos = $pos_388; + $_403 = FALSE; break; } while(0); - if( $_395 === TRUE ) { $_397 = TRUE; break; } - $result = $res_378; - $this->pos = $pos_378; - $_397 = FALSE; break; + if( $_403 === TRUE ) { $_405 = TRUE; break; } + $result = $res_386; + $this->pos = $pos_386; + $_405 = FALSE; break; } while(0); - if( $_397 === TRUE ) { $_399 = TRUE; break; } - $result = $res_376; - $this->pos = $pos_376; - $_399 = FALSE; break; + if( $_405 === TRUE ) { $_407 = TRUE; break; } + $result = $res_384; + $this->pos = $pos_384; + $_407 = FALSE; break; } while(0); - if( $_399 === TRUE ) { $_401 = TRUE; break; } - $result = $res_374; - $this->pos = $pos_374; - $_401 = FALSE; break; + if( $_407 === TRUE ) { $_409 = TRUE; break; } + $result = $res_382; + $this->pos = $pos_382; + $_409 = FALSE; break; } while(0); - if( $_401 === TRUE ) { $_403 = TRUE; break; } - $result = $res_372; - $this->pos = $pos_372; - $_403 = FALSE; break; + if( $_409 === TRUE ) { $_411 = TRUE; break; } + $result = $res_380; + $this->pos = $pos_380; + $_411 = FALSE; break; } while(0); - if( $_403 === FALSE) { $_405 = FALSE; break; } - $_405 = TRUE; break; + if( $_411 === FALSE) { $_413 = FALSE; break; } + $_413 = TRUE; break; } while(0); - if( $_405 === FALSE) { - $result = $res_406; - $this->pos = $pos_406; - unset( $res_406 ); - unset( $pos_406 ); + if( $_413 === FALSE) { + $result = $res_414; + $this->pos = $pos_414; + unset( $res_414 ); + unset( $pos_414 ); break; } $count += 1; diff --git a/core/SSTemplateParser.php.inc b/core/SSTemplateParser.php.inc index 2d430320d..03442d539 100644 --- a/core/SSTemplateParser.php.inc +++ b/core/SSTemplateParser.php.inc @@ -277,17 +277,25 @@ class SSTemplateParser extends Parser { # which checks if the argument given is present or not. For explicit strings (which were not allowed in 2.4) # this falls back to simple truthiness check - PresenceCheck: Argument + PresenceCheck: (Not:'not' <)? Argument */ + function PresenceCheck__construct(&$res) { + $res['php'] = ''; + } + + function PresenceCheck_Not(&$res, $sub) { + $res['php'] = '!'; + } + function PresenceCheck_Argument(&$res, $sub) { if ($sub['ArgumentMode'] == 'string') { - $res['php'] = '((bool)'.$sub['php'].')'; + $res['php'] .= '((bool)'.$sub['php'].')'; } else { $php = ($sub['ArgumentMode'] == 'default' ? $sub['lookup_php'] : $sub['php']); // TODO: kinda hacky - maybe we need a way to pass state down the parse chain so // Lookup_LastLookupStep and Argument_BareWord can produce hasValue instead of XML_val - $res['php'] = str_replace('$$FINAL', 'hasValue', $php); + $res['php'] .= str_replace('$$FINAL', 'hasValue', $php); } } @@ -329,8 +337,8 @@ class SSTemplateParser extends Parser { # can have else_if and else tags in between the if tag and the end_if tag, and (B) they have a different # argument structure to every other block - IfPart: '<%' < 'if' < :IfArgument > '%>' :Template? - ElseIfPart: '<%' < 'else_if' < :IfArgument > '%>' :Template? + IfPart: '<%' < 'if' [ :IfArgument > '%>' :Template? + ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' :Template? ElsePart: '<%' < 'else' > '%>' :Template? If: IfPart ElseIfPart* ElsePart? '<%' < 'end_if' > '%>' diff --git a/tests/SSViewerTest.php b/tests/SSViewerTest.php index 874d50dd0..8794e7753 100644 --- a/tests/SSViewerTest.php +++ b/tests/SSViewerTest.php @@ -227,6 +227,12 @@ after') $this->assertEquals('ABD', $this->render('A<% if IsSet(Param) %>B<% else %>C<% end_if %>D')); + // Negation + $this->assertEquals('AC', + $this->render('A<% if not IsSet %>B<% end_if %>C')); + $this->assertEquals('ABC', + $this->render('A<% if not NotSet %>B<% end_if %>C')); + // Or $this->assertEquals('ABD', $this->render('A<% if IsSet || NotSet %>B<% else_if A %>C<% end_if %>D')); @@ -238,6 +244,14 @@ after') $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet || NotSet %>C<% end_if %>D')); $this->assertEquals('AD', $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet2 || NotSet3 %>C<% end_if %>D')); + + // Negated Or + $this->assertEquals('ACD', + $this->render('A<% if not IsSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D')); + $this->assertEquals('ABD', + $this->render('A<% if not NotSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D')); + $this->assertEquals('ABD', + $this->render('A<% if NotSet || not AlsoNotSet %>B<% else_if A %>C<% end_if %>D')); // And $this->assertEquals('ABD', @@ -432,8 +446,8 @@ after') '<% loop $Foo %> $Name <% with $Sub %> - $Name< - % loop $Up %>$Name<% end_loop %> + $Name + <% loop $Up %>$Name<% end_loop %> $Name <% end_with %> $Name From 20ba97f8ff6d9f84d42d5753f66424fdc3dd8893 Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Mon, 21 Feb 2011 16:19:10 +1300 Subject: [PATCH 10/15] BUGFIX: Empty if blocks are allowed (were hacky way of doing negation, now replaced by not) --- core/SSTemplateParser.php | 26 ++++++-------------------- core/SSTemplateParser.php.inc | 8 ++++---- tests/SSViewerTest.php | 4 ++++ 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/core/SSTemplateParser.php b/core/SSTemplateParser.php index 0cb40a392..52091b8dd 100644 --- a/core/SSTemplateParser.php +++ b/core/SSTemplateParser.php @@ -1029,7 +1029,7 @@ class SSTemplateParser extends Parser { } - /* ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' :Template? */ + /* ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' :Template */ function match_ElseIfPart ($substack = array()) { $result = $this->construct( "ElseIfPart" ); $_162 = NULL; @@ -1053,19 +1053,12 @@ class SSTemplateParser extends Parser { $_159 = new ParserExpression( $this, $substack, $result ); if (( $subres = $this->literal( $_159->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } else { $_162 = FALSE; break; } - $res_161 = $result; - $pos_161 = $this->pos; $key = "Template"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Template" ); } - else { - $result = $res_161; - $this->pos = $pos_161; - unset( $res_161 ); - unset( $pos_161 ); - } + else { $_162 = FALSE; break; } $_162 = TRUE; break; } while(0); @@ -1076,7 +1069,7 @@ class SSTemplateParser extends Parser { } - /* ElsePart: '<%' < 'else' > '%>' :Template? */ + /* ElsePart: '<%' < 'else' > '%>' :Template */ function match_ElsePart ($substack = array()) { $result = $this->construct( "ElsePart" ); $_173 = NULL; @@ -1092,19 +1085,12 @@ class SSTemplateParser extends Parser { $_170 = new ParserExpression( $this, $substack, $result ); if (( $subres = $this->literal( $_170->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } else { $_173 = FALSE; break; } - $res_172 = $result; - $pos_172 = $this->pos; $key = "Template"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Template" ); } - else { - $result = $res_172; - $this->pos = $pos_172; - unset( $res_172 ); - unset( $pos_172 ); - } + else { $_173 = FALSE; break; } $_173 = TRUE; break; } while(0); @@ -1174,14 +1160,14 @@ class SSTemplateParser extends Parser { function If_IfPart(&$res, $sub) { $res['php'] = 'if (' . $sub['IfArgument']['php'] . ') { ' . PHP_EOL . - $sub['Template']['php'] . PHP_EOL . + (isset($sub['Template']) ? $sub['Template']['php'] : '') . PHP_EOL . '}'; } function If_ElseIfPart(&$res, $sub) { $res['php'] .= 'else if (' . $sub['IfArgument']['php'] . ') { ' . PHP_EOL . - $sub['Template']['php'] . PHP_EOL . + $sub['Template']['php'] . PHP_EOL . '}'; } diff --git a/core/SSTemplateParser.php.inc b/core/SSTemplateParser.php.inc index 03442d539..cc5d28a1c 100644 --- a/core/SSTemplateParser.php.inc +++ b/core/SSTemplateParser.php.inc @@ -338,22 +338,22 @@ class SSTemplateParser extends Parser { # argument structure to every other block IfPart: '<%' < 'if' [ :IfArgument > '%>' :Template? - ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' :Template? - ElsePart: '<%' < 'else' > '%>' :Template? + ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' :Template + ElsePart: '<%' < 'else' > '%>' :Template If: IfPart ElseIfPart* ElsePart? '<%' < 'end_if' > '%>' */ function If_IfPart(&$res, $sub) { $res['php'] = 'if (' . $sub['IfArgument']['php'] . ') { ' . PHP_EOL . - $sub['Template']['php'] . PHP_EOL . + (isset($sub['Template']) ? $sub['Template']['php'] : '') . PHP_EOL . '}'; } function If_ElseIfPart(&$res, $sub) { $res['php'] .= 'else if (' . $sub['IfArgument']['php'] . ') { ' . PHP_EOL . - $sub['Template']['php'] . PHP_EOL . + $sub['Template']['php'] . PHP_EOL . '}'; } diff --git a/tests/SSViewerTest.php b/tests/SSViewerTest.php index 8794e7753..978a56b70 100644 --- a/tests/SSViewerTest.php +++ b/tests/SSViewerTest.php @@ -278,6 +278,10 @@ after') // Else $this->assertEquals('ADE', $this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% else %>D<% end_if %>E')); + + // Empty if with else + $this->assertEquals('ABC', + $this->render('A<% if NotSet %><% else %>B<% end_if %>C')); } function testBaseTagGeneration() { From 0b7d396ab874a17fe921331c53e35e487a69781f Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Mon, 21 Feb 2011 17:44:46 +1300 Subject: [PATCH 11/15] ENHANCEMENT: Add old-style _t and sprintf(_t) tags back into new SSViewer rewrite --- core/SSTemplateParser.php | 1223 ++++++++++++++++++++------------- core/SSTemplateParser.php.inc | 82 ++- core/SSViewer.php | 42 +- 3 files changed, 857 insertions(+), 490 deletions(-) diff --git a/core/SSTemplateParser.php b/core/SSTemplateParser.php index 52091b8dd..55066f984 100644 --- a/core/SSTemplateParser.php +++ b/core/SSTemplateParser.php @@ -670,7 +670,7 @@ class SSTemplateParser extends Parser { function Argument_QuotedString(&$res, $sub) { $res['ArgumentMode'] = 'string'; - $res['php'] = "'" . $sub['String']['text'] . "'"; + $res['php'] = "'" . str_replace("'", "\\'", $sub['String']['text']) . "'"; } function Argument_Lookup(&$res, $sub) { @@ -687,7 +687,7 @@ class SSTemplateParser extends Parser { function Argument_FreeString(&$res, $sub) { $res['ArgumentMode'] = 'string'; - $res['php'] = "'" . $sub['text'] . "'"; + $res['php'] = "'" . str_replace("'", "\\'", $sub['text']) . "'"; } /* ComparisonOperator: "==" | "!=" | "=" */ @@ -1250,210 +1250,429 @@ class SSTemplateParser extends Parser { function Require_Call(&$res, $sub) { $res['php'] = "Requirements::".$sub['Method']['text'].'('.$sub['CallArguments']['php'].');'; } + + /* OldTPart: "_t" < "(" < QuotedString (< "," < CallArguments)? > ")" */ + function match_OldTPart ($substack = array()) { + $result = $this->construct( "OldTPart" ); + $_222 = NULL; + do { + $_208 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_208->expand("_t") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_222 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == "(") { + $this->pos += 1; + $result["text"] .= "("; + } + else { $_222 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "QuotedString"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_QuotedString(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_222 = FALSE; break; } + $res_219 = $result; + $pos_219 = $this->pos; + $_218 = NULL; + do { + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == ",") { + $this->pos += 1; + $result["text"] .= ","; + } + else { $_218 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "CallArguments"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_CallArguments(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_218 = FALSE; break; } + $_218 = TRUE; break; + } + while(0); + if( $_218 === FALSE) { + $result = $res_219; + $this->pos = $pos_219; + unset( $res_219 ); + unset( $pos_219 ); + } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == ")") { + $this->pos += 1; + $result["text"] .= ")"; + } + else { $_222 = FALSE; break; } + $_222 = TRUE; break; + } + while(0); + if( $_222 === TRUE ) { + return $this->finalise( "OldTPart", $result ); + } + if( $_222 === FALSE) { return FALSE; } + } + + + + function OldTPart__construct(&$res) { + $res['php'] = "_t("; + } + + function OldTPart_QuotedString(&$res, $sub) { + $entity = $sub['String']['text']; + if (strpos($entity, '.') === false) { + $res['php'] .= "\$scope->XML_val('I18NNamespace').'.$entity'"; + } + else { + $res['php'] .= "'$entity'"; + } + } + + function OldTPart_CallArguments(&$res, $sub) { + $res['php'] .= ',' . $sub['php']; + } + + function OldTPart__finalise(&$res) { + $res['php'] .= ')'; + } + + /* OldTTag: "<%" < OldTPart > "%>" */ + function match_OldTTag ($substack = array()) { + $result = $this->construct( "OldTTag" ); + $_231 = NULL; + do { + $_224 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_224->expand("<%") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_231 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "OldTPart"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OldTPart(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_231 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_229 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_229->expand("%>") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_231 = FALSE; break; } + $_231 = TRUE; break; + } + while(0); + if( $_231 === TRUE ) { + return $this->finalise( "OldTTag", $result ); + } + if( $_231 === FALSE) { return FALSE; } + } + + + + function OldTTag_OldTPart(&$res, $sub) { + $res['php'] = $sub['php']; + } + + /* OldSprintfTag: "<%" < "sprintf" < "(" < OldTPart < "," < CallArguments > ")" > "%>" */ + function match_OldSprintfTag ($substack = array()) { + $result = $this->construct( "OldSprintfTag" ); + $_251 = NULL; + do { + $_233 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_233->expand("<%") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_251 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_236 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_236->expand("sprintf") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_251 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == "(") { + $this->pos += 1; + $result["text"] .= "("; + } + else { $_251 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "OldTPart"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OldTPart(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_251 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == ",") { + $this->pos += 1; + $result["text"] .= ","; + } + else { $_251 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $key = "CallArguments"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_CallArguments(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_251 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == ")") { + $this->pos += 1; + $result["text"] .= ")"; + } + else { $_251 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $_249 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_249->expand("%>") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_251 = FALSE; break; } + $_251 = TRUE; break; + } + while(0); + if( $_251 === TRUE ) { + return $this->finalise( "OldSprintfTag", $result ); + } + if( $_251 === FALSE) { return FALSE; } + } + + + + function OldSprintfTag__construct(&$res) { + $res['php'] = "sprintf("; + } + + function OldSprintfTag_OldTPart(&$res, $sub) { + $res['php'] .= $sub['php']; + } + + function OldSprintfTag_CallArguments(&$res, $sub) { + $res['php'] .= ',' . $sub['php'] . ')'; + } + + /* OldI18NTag: OldSprintfTag | OldTTag */ + function match_OldI18NTag ($substack = array()) { + $result = $this->construct( "OldI18NTag" ); + $_256 = NULL; + do { + $res_253 = $result; + $pos_253 = $this->pos; + $key = "OldSprintfTag"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OldSprintfTag(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_256 = TRUE; break; + } + $result = $res_253; + $this->pos = $pos_253; + $key = "OldTTag"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OldTTag(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_256 = TRUE; break; + } + $result = $res_253; + $this->pos = $pos_253; + $_256 = FALSE; break; + } + while(0); + if( $_256 === TRUE ) { + return $this->finalise( "OldI18NTag", $result ); + } + if( $_256 === FALSE) { return FALSE; } + } + + + + function OldI18NTag_STR(&$res, $sub) { + $res['php'] = '$val .= ' . $sub['php'] . ';'; + } /* BlockArguments: :Argument ( < "," < :Argument)* */ function match_BlockArguments ($substack = array()) { $result = $this->construct( "BlockArguments" ); - $_215 = NULL; + $_265 = NULL; do { $key = "Argument"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Argument" ); } - else { $_215 = FALSE; break; } + else { $_265 = FALSE; break; } while (true) { - $res_214 = $result; - $pos_214 = $this->pos; - $_213 = NULL; + $res_264 = $result; + $pos_264 = $this->pos; + $_263 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } if (substr($this->string,$this->pos,1) == ",") { $this->pos += 1; $result["text"] .= ","; } - else { $_213 = FALSE; break; } + else { $_263 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $key = "Argument"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Argument" ); } - else { $_213 = FALSE; break; } - $_213 = TRUE; break; + else { $_263 = FALSE; break; } + $_263 = TRUE; break; } while(0); - if( $_213 === FALSE) { - $result = $res_214; - $this->pos = $pos_214; - unset( $res_214 ); - unset( $pos_214 ); + if( $_263 === FALSE) { + $result = $res_264; + $this->pos = $pos_264; + unset( $res_264 ); + unset( $pos_264 ); break; } } - $_215 = TRUE; break; + $_265 = TRUE; break; } while(0); - if( $_215 === TRUE ) { + if( $_265 === TRUE ) { return $this->finalise( "BlockArguments", $result ); } - if( $_215 === FALSE) { return FALSE; } + if( $_265 === FALSE) { return FALSE; } } /* NotBlockTag: "end_" | (("if" | "else_if" | "else" | "require") ] ) */ function match_NotBlockTag ($substack = array()) { $result = $this->construct( "NotBlockTag" ); - $_242 = NULL; + $_292 = NULL; do { - $res_217 = $result; - $pos_217 = $this->pos; - $_218 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_218->expand("end_") ) ) !== FALSE) { + $res_267 = $result; + $pos_267 = $this->pos; + $_268 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_268->expand("end_") ) ) !== FALSE) { $result["text"] .= $subres; - $_242 = TRUE; break; + $_292 = TRUE; break; } - $result = $res_217; - $this->pos = $pos_217; - $_240 = NULL; + $result = $res_267; + $this->pos = $pos_267; + $_290 = NULL; do { - $_237 = NULL; + $_287 = NULL; do { - $_235 = NULL; + $_285 = NULL; do { - $res_220 = $result; - $pos_220 = $this->pos; - $_221 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_221->expand("if") ) ) !== FALSE) { + $res_270 = $result; + $pos_270 = $this->pos; + $_271 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_271->expand("if") ) ) !== FALSE) { $result["text"] .= $subres; - $_235 = TRUE; break; + $_285 = TRUE; break; } - $result = $res_220; - $this->pos = $pos_220; - $_233 = NULL; + $result = $res_270; + $this->pos = $pos_270; + $_283 = NULL; do { - $res_223 = $result; - $pos_223 = $this->pos; - $_224 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_224->expand("else_if") ) ) !== FALSE) { + $res_273 = $result; + $pos_273 = $this->pos; + $_274 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_274->expand("else_if") ) ) !== FALSE) { $result["text"] .= $subres; - $_233 = TRUE; break; + $_283 = TRUE; break; } - $result = $res_223; - $this->pos = $pos_223; - $_231 = NULL; + $result = $res_273; + $this->pos = $pos_273; + $_281 = NULL; do { - $res_226 = $result; - $pos_226 = $this->pos; - $_227 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_227->expand("else") ) ) !== FALSE) { + $res_276 = $result; + $pos_276 = $this->pos; + $_277 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_277->expand("else") ) ) !== FALSE) { $result["text"] .= $subres; - $_231 = TRUE; break; + $_281 = TRUE; break; } - $result = $res_226; - $this->pos = $pos_226; - $_229 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_229->expand("require") ) ) !== FALSE) { + $result = $res_276; + $this->pos = $pos_276; + $_279 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_279->expand("require") ) ) !== FALSE) { $result["text"] .= $subres; - $_231 = TRUE; break; + $_281 = TRUE; break; } - $result = $res_226; - $this->pos = $pos_226; - $_231 = FALSE; break; + $result = $res_276; + $this->pos = $pos_276; + $_281 = FALSE; break; } while(0); - if( $_231 === TRUE ) { $_233 = TRUE; break; } - $result = $res_223; - $this->pos = $pos_223; - $_233 = FALSE; break; + if( $_281 === TRUE ) { $_283 = TRUE; break; } + $result = $res_273; + $this->pos = $pos_273; + $_283 = FALSE; break; } while(0); - if( $_233 === TRUE ) { $_235 = TRUE; break; } - $result = $res_220; - $this->pos = $pos_220; - $_235 = FALSE; break; + if( $_283 === TRUE ) { $_285 = TRUE; break; } + $result = $res_270; + $this->pos = $pos_270; + $_285 = FALSE; break; } while(0); - if( $_235 === FALSE) { $_237 = FALSE; break; } - $_237 = TRUE; break; + if( $_285 === FALSE) { $_287 = FALSE; break; } + $_287 = TRUE; break; } while(0); - if( $_237 === FALSE) { $_240 = FALSE; break; } + if( $_287 === FALSE) { $_290 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_240 = FALSE; break; } - $_240 = TRUE; break; + else { $_290 = FALSE; break; } + $_290 = TRUE; break; } while(0); - if( $_240 === TRUE ) { $_242 = TRUE; break; } - $result = $res_217; - $this->pos = $pos_217; - $_242 = FALSE; break; + if( $_290 === TRUE ) { $_292 = TRUE; break; } + $result = $res_267; + $this->pos = $pos_267; + $_292 = FALSE; break; } while(0); - if( $_242 === TRUE ) { + if( $_292 === TRUE ) { return $this->finalise( "NotBlockTag", $result ); } - if( $_242 === FALSE) { return FALSE; } + if( $_292 === FALSE) { return FALSE; } } /* ClosedBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > Zap:'%>' :Template? '<%' < 'end_' '$BlockName' > '%>' */ function match_ClosedBlock ($substack = array()) { $result = $this->construct( "ClosedBlock" ); - $_269 = NULL; + $_319 = NULL; do { - $_244 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_244->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_269 = FALSE; break; } + $_294 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_294->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_319 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_247 = $result; - $pos_247 = $this->pos; + $res_297 = $result; + $pos_297 = $this->pos; $key = "NotBlockTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $result = $res_247; - $this->pos = $pos_247; - $_269 = FALSE; break; + $result = $res_297; + $this->pos = $pos_297; + $_319 = FALSE; break; } else { - $result = $res_247; - $this->pos = $pos_247; + $result = $res_297; + $this->pos = $pos_297; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockName" ); } - else { $_269 = FALSE; break; } - $res_253 = $result; - $pos_253 = $this->pos; - $_252 = NULL; + else { $_319 = FALSE; break; } + $res_303 = $result; + $pos_303 = $this->pos; + $_302 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_252 = FALSE; break; } + else { $_302 = FALSE; break; } $key = "BlockArguments"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockArguments" ); } - else { $_252 = FALSE; break; } + else { $_302 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_252 = FALSE; break; } - $_252 = TRUE; break; + else { $_302 = FALSE; break; } + $_302 = TRUE; break; } while(0); - if( $_252 === FALSE) { - $result = $res_253; - $this->pos = $pos_253; - unset( $res_253 ); - unset( $pos_253 ); + if( $_302 === FALSE) { + $result = $res_303; + $this->pos = $pos_303; + unset( $res_303 ); + unset( $pos_303 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $substack[] = $result; $result = $this->construct( "Zap" ); - $_255 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_255->expand('%>') ) ) !== FALSE) { + $_305 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_305->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; $subres = $result ; $result = array_pop( $substack ) ; @@ -1461,42 +1680,42 @@ class SSTemplateParser extends Parser { } else { $result = array_pop( $substack ) ; - $_269 = FALSE; break; + $_319 = FALSE; break; } - $res_258 = $result; - $pos_258 = $this->pos; + $res_308 = $result; + $pos_308 = $this->pos; $key = "Template"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Template" ); } else { - $result = $res_258; - $this->pos = $pos_258; - unset( $res_258 ); - unset( $pos_258 ); + $result = $res_308; + $this->pos = $pos_308; + unset( $res_308 ); + unset( $pos_308 ); } - $_259 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_259->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_269 = FALSE; break; } + $_309 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_309->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_319 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_262 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_262->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_269 = FALSE; break; } - $_264 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_264->expand('$BlockName') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_269 = FALSE; break; } + $_312 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_312->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_319 = FALSE; break; } + $_314 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_314->expand('$BlockName') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_319 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_267 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_267->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_269 = FALSE; break; } - $_269 = TRUE; break; + $_317 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_317->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_319 = FALSE; break; } + $_319 = TRUE; break; } while(0); - if( $_269 === TRUE ) { + if( $_319 === TRUE ) { return $this->finalise( "ClosedBlock", $result ); } - if( $_269 === FALSE) { return FALSE; } + if( $_319 === FALSE) { return FALSE; } } @@ -1592,66 +1811,66 @@ class SSTemplateParser extends Parser { /* OpenBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > '%>' */ function match_OpenBlock ($substack = array()) { $result = $this->construct( "OpenBlock" ); - $_284 = NULL; + $_334 = NULL; do { - $_271 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_271->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_284 = FALSE; break; } + $_321 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_321->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_334 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_274 = $result; - $pos_274 = $this->pos; + $res_324 = $result; + $pos_324 = $this->pos; $key = "NotBlockTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $result = $res_274; - $this->pos = $pos_274; - $_284 = FALSE; break; + $result = $res_324; + $this->pos = $pos_324; + $_334 = FALSE; break; } else { - $result = $res_274; - $this->pos = $pos_274; + $result = $res_324; + $this->pos = $pos_324; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockName" ); } - else { $_284 = FALSE; break; } - $res_280 = $result; - $pos_280 = $this->pos; - $_279 = NULL; + else { $_334 = FALSE; break; } + $res_330 = $result; + $pos_330 = $this->pos; + $_329 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_279 = FALSE; break; } + else { $_329 = FALSE; break; } $key = "BlockArguments"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockArguments" ); } - else { $_279 = FALSE; break; } + else { $_329 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_279 = FALSE; break; } - $_279 = TRUE; break; + else { $_329 = FALSE; break; } + $_329 = TRUE; break; } while(0); - if( $_279 === FALSE) { - $result = $res_280; - $this->pos = $pos_280; - unset( $res_280 ); - unset( $pos_280 ); + if( $_329 === FALSE) { + $result = $res_330; + $this->pos = $pos_330; + unset( $res_330 ); + unset( $pos_330 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_282 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_282->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_284 = FALSE; break; } - $_284 = TRUE; break; + $_332 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_332->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_334 = FALSE; break; } + $_334 = TRUE; break; } while(0); - if( $_284 === TRUE ) { + if( $_334 === TRUE ) { return $this->finalise( "OpenBlock", $result ); } - if( $_284 === FALSE) { return FALSE; } + if( $_334 === FALSE) { return FALSE; } } @@ -1739,30 +1958,30 @@ class SSTemplateParser extends Parser { /* MismatchedEndBlock: '<%' < 'end_' Word > '%>' */ function match_MismatchedEndBlock ($substack = array()) { $result = $this->construct( "MismatchedEndBlock" ); - $_295 = NULL; + $_345 = NULL; do { - $_286 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_286->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_295 = FALSE; break; } + $_336 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_336->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_345 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_289 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_289->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_295 = FALSE; break; } + $_339 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_339->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_345 = FALSE; break; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_295 = FALSE; break; } + else { $_345 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_293 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_293->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_295 = FALSE; break; } - $_295 = TRUE; break; + $_343 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_343->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_345 = FALSE; break; } + $_345 = TRUE; break; } while(0); - if( $_295 === TRUE ) { + if( $_345 === TRUE ) { return $this->finalise( "MismatchedEndBlock", $result ); } - if( $_295 === FALSE) { return FALSE; } + if( $_345 === FALSE) { return FALSE; } } @@ -1775,82 +1994,82 @@ class SSTemplateParser extends Parser { /* MalformedOpenTag: '<%' < !NotBlockTag Tag:Word !( ( [ :BlockArguments ] )? > '%>' ) */ function match_MalformedOpenTag ($substack = array()) { $result = $this->construct( "MalformedOpenTag" ); - $_312 = NULL; + $_362 = NULL; do { - $_297 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_297->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_312 = FALSE; break; } + $_347 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_347->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_362 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_300 = $result; - $pos_300 = $this->pos; + $res_350 = $result; + $pos_350 = $this->pos; $key = "NotBlockTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $result = $res_300; - $this->pos = $pos_300; - $_312 = FALSE; break; + $result = $res_350; + $this->pos = $pos_350; + $_362 = FALSE; break; } else { - $result = $res_300; - $this->pos = $pos_300; + $result = $res_350; + $this->pos = $pos_350; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Tag" ); } - else { $_312 = FALSE; break; } - $res_311 = $result; - $pos_311 = $this->pos; - $_310 = NULL; + else { $_362 = FALSE; break; } + $res_361 = $result; + $pos_361 = $this->pos; + $_360 = NULL; do { - $res_306 = $result; - $pos_306 = $this->pos; - $_305 = NULL; + $res_356 = $result; + $pos_356 = $this->pos; + $_355 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_305 = FALSE; break; } + else { $_355 = FALSE; break; } $key = "BlockArguments"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockArguments" ); } - else { $_305 = FALSE; break; } + else { $_355 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_305 = FALSE; break; } - $_305 = TRUE; break; + else { $_355 = FALSE; break; } + $_355 = TRUE; break; } while(0); - if( $_305 === FALSE) { - $result = $res_306; - $this->pos = $pos_306; - unset( $res_306 ); - unset( $pos_306 ); + if( $_355 === FALSE) { + $result = $res_356; + $this->pos = $pos_356; + unset( $res_356 ); + unset( $pos_356 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_308 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_308->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_310 = FALSE; break; } - $_310 = TRUE; break; + $_358 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_358->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_360 = FALSE; break; } + $_360 = TRUE; break; } while(0); - if( $_310 === TRUE ) { - $result = $res_311; - $this->pos = $pos_311; - $_312 = FALSE; break; + if( $_360 === TRUE ) { + $result = $res_361; + $this->pos = $pos_361; + $_362 = FALSE; break; } - if( $_310 === FALSE) { - $result = $res_311; - $this->pos = $pos_311; + if( $_360 === FALSE) { + $result = $res_361; + $this->pos = $pos_361; } - $_312 = TRUE; break; + $_362 = TRUE; break; } while(0); - if( $_312 === TRUE ) { + if( $_362 === TRUE ) { return $this->finalise( "MalformedOpenTag", $result ); } - if( $_312 === FALSE) { return FALSE; } + if( $_362 === FALSE) { return FALSE; } } @@ -1863,64 +2082,64 @@ class SSTemplateParser extends Parser { /* MalformedCloseTag: '<%' < Tag:('end_' :Word ) !( > '%>' ) */ function match_MalformedCloseTag ($substack = array()) { $result = $this->construct( "MalformedCloseTag" ); - $_328 = NULL; + $_378 = NULL; do { - $_314 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_314->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_328 = FALSE; break; } + $_364 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_364->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_378 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } $substack[] = $result; $result = $this->construct( "Tag" ); - $_320 = NULL; + $_370 = NULL; do { - $_317 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_317->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_320 = FALSE; break; } + $_367 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_367->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_370 = FALSE; break; } $key = "Word"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Word" ); } - else { $_320 = FALSE; break; } - $_320 = TRUE; break; + else { $_370 = FALSE; break; } + $_370 = TRUE; break; } while(0); - if( $_320 === TRUE ) { + if( $_370 === TRUE ) { $subres = $result ; $result = array_pop( $substack ) ; $this->store( $result, $subres, 'Tag' ); } - if( $_320 === FALSE) { + if( $_370 === FALSE) { $result = array_pop( $substack ) ; - $_328 = FALSE; break; + $_378 = FALSE; break; } - $res_327 = $result; - $pos_327 = $this->pos; - $_326 = NULL; + $res_377 = $result; + $pos_377 = $this->pos; + $_376 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_324 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_324->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_326 = FALSE; break; } - $_326 = TRUE; break; + $_374 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_374->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_376 = FALSE; break; } + $_376 = TRUE; break; } while(0); - if( $_326 === TRUE ) { - $result = $res_327; - $this->pos = $pos_327; - $_328 = FALSE; break; + if( $_376 === TRUE ) { + $result = $res_377; + $this->pos = $pos_377; + $_378 = FALSE; break; } - if( $_326 === FALSE) { - $result = $res_327; - $this->pos = $pos_327; + if( $_376 === FALSE) { + $result = $res_377; + $this->pos = $pos_377; } - $_328 = TRUE; break; + $_378 = TRUE; break; } while(0); - if( $_328 === TRUE ) { + if( $_378 === TRUE ) { return $this->finalise( "MalformedCloseTag", $result ); } - if( $_328 === FALSE) { return FALSE; } + if( $_378 === FALSE) { return FALSE; } } @@ -1933,33 +2152,33 @@ class SSTemplateParser extends Parser { /* MalformedBlock: MalformedOpenTag | MalformedCloseTag */ function match_MalformedBlock ($substack = array()) { $result = $this->construct( "MalformedBlock" ); - $_333 = NULL; + $_383 = NULL; do { - $res_330 = $result; - $pos_330 = $this->pos; + $res_380 = $result; + $pos_380 = $this->pos; $key = "MalformedOpenTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedOpenTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_333 = TRUE; break; + $_383 = TRUE; break; } - $result = $res_330; - $this->pos = $pos_330; + $result = $res_380; + $this->pos = $pos_380; $key = "MalformedCloseTag"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedCloseTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_333 = TRUE; break; + $_383 = TRUE; break; } - $result = $res_330; - $this->pos = $pos_330; - $_333 = FALSE; break; + $result = $res_380; + $this->pos = $pos_380; + $_383 = FALSE; break; } while(0); - if( $_333 === TRUE ) { + if( $_383 === TRUE ) { return $this->finalise( "MalformedBlock", $result ); } - if( $_333 === FALSE) { return FALSE; } + if( $_383 === FALSE) { return FALSE; } } @@ -1968,57 +2187,57 @@ class SSTemplateParser extends Parser { /* Comment: "<%--" (!"--%>" /./)+ "--%>" */ function match_Comment ($substack = array()) { $result = $this->construct( "Comment" ); - $_345 = NULL; + $_395 = NULL; do { - $_335 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_335->expand("<%--") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_345 = FALSE; break; } + $_385 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_385->expand("<%--") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_395 = FALSE; break; } $count = 0; while (true) { - $res_342 = $result; - $pos_342 = $this->pos; - $_341 = NULL; + $res_392 = $result; + $pos_392 = $this->pos; + $_391 = NULL; do { - $res_338 = $result; - $pos_338 = $this->pos; - $_337 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_337->expand("--%>") ) ) !== FALSE) { + $res_388 = $result; + $pos_388 = $this->pos; + $_387 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_387->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; - $result = $res_338; - $this->pos = $pos_338; - $_341 = FALSE; break; + $result = $res_388; + $this->pos = $pos_388; + $_391 = FALSE; break; } else { - $result = $res_338; - $this->pos = $pos_338; + $result = $res_388; + $this->pos = $pos_388; } - $_339 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_339->expand('/./') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_341 = FALSE; break; } - $_341 = TRUE; break; + $_389 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_389->expand('/./') ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_391 = FALSE; break; } + $_391 = TRUE; break; } while(0); - if( $_341 === FALSE) { - $result = $res_342; - $this->pos = $pos_342; - unset( $res_342 ); - unset( $pos_342 ); + if( $_391 === FALSE) { + $result = $res_392; + $this->pos = $pos_392; + unset( $res_392 ); + unset( $pos_392 ); break; } $count += 1; } if ($count > 0) { } - else { $_345 = FALSE; break; } - $_343 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_343->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_345 = FALSE; break; } - $_345 = TRUE; break; + else { $_395 = FALSE; break; } + $_393 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->literal( $_393->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_395 = FALSE; break; } + $_395 = TRUE; break; } while(0); - if( $_345 === TRUE ) { + if( $_395 === TRUE ) { return $this->finalise( "Comment", $result ); } - if( $_345 === FALSE) { return FALSE; } + if( $_395 === FALSE) { return FALSE; } } @@ -2039,8 +2258,8 @@ class SSTemplateParser extends Parser { / */ function match_Text ($substack = array()) { $result = array("name"=>"Text", "text"=>""); - $_347 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_347->expand('/ + $_397 = new ParserExpression( $this, $substack, $result ); + if (( $subres = $this->rx( $_397->expand('/ ( (\\\\.) | # Any escaped character ([^<${]) | # Any character that isn\'t <, $ or { @@ -2057,155 +2276,173 @@ class SSTemplateParser extends Parser { } - /* Template: (Comment | If | Require | ClosedBlock | OpenBlock | MalformedBlock | Injection | Text)+ */ + /* Template: (Comment | If | Require | OldI18NTag | ClosedBlock | OpenBlock | MalformedBlock | Injection | Text)+ */ function match_Template ($substack = array()) { $result = $this->construct( "Template" ); $count = 0; while (true) { - $res_379 = $result; - $pos_379 = $this->pos; - $_378 = NULL; + $res_433 = $result; + $pos_433 = $this->pos; + $_432 = NULL; do { - $_376 = NULL; + $_430 = NULL; do { - $res_349 = $result; - $pos_349 = $this->pos; + $res_399 = $result; + $pos_399 = $this->pos; $key = "Comment"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comment(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_376 = TRUE; break; + $_430 = TRUE; break; } - $result = $res_349; - $this->pos = $pos_349; - $_374 = NULL; + $result = $res_399; + $this->pos = $pos_399; + $_428 = NULL; do { - $res_351 = $result; - $pos_351 = $this->pos; + $res_401 = $result; + $pos_401 = $this->pos; $key = "If"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_If(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_374 = TRUE; break; + $_428 = TRUE; break; } - $result = $res_351; - $this->pos = $pos_351; - $_372 = NULL; + $result = $res_401; + $this->pos = $pos_401; + $_426 = NULL; do { - $res_353 = $result; - $pos_353 = $this->pos; + $res_403 = $result; + $pos_403 = $this->pos; $key = "Require"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Require(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_372 = TRUE; break; + $_426 = TRUE; break; } - $result = $res_353; - $this->pos = $pos_353; - $_370 = NULL; + $result = $res_403; + $this->pos = $pos_403; + $_424 = NULL; do { - $res_355 = $result; - $pos_355 = $this->pos; - $key = "ClosedBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); + $res_405 = $result; + $pos_405 = $this->pos; + $key = "OldI18NTag"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OldI18NTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_370 = TRUE; break; + $_424 = TRUE; break; } - $result = $res_355; - $this->pos = $pos_355; - $_368 = NULL; + $result = $res_405; + $this->pos = $pos_405; + $_422 = NULL; do { - $res_357 = $result; - $pos_357 = $this->pos; - $key = "OpenBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); + $res_407 = $result; + $pos_407 = $this->pos; + $key = "ClosedBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_368 = TRUE; break; + $_422 = TRUE; break; } - $result = $res_357; - $this->pos = $pos_357; - $_366 = NULL; + $result = $res_407; + $this->pos = $pos_407; + $_420 = NULL; do { - $res_359 = $result; - $pos_359 = $this->pos; - $key = "MalformedBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); + $res_409 = $result; + $pos_409 = $this->pos; + $key = "OpenBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_366 = TRUE; break; + $_420 = TRUE; break; } - $result = $res_359; - $this->pos = $pos_359; - $_364 = NULL; + $result = $res_409; + $this->pos = $pos_409; + $_418 = NULL; do { - $res_361 = $result; - $pos_361 = $this->pos; - $key = "Injection"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); + $res_411 = $result; + $pos_411 = $this->pos; + $key = "MalformedBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_364 = TRUE; break; + $_418 = TRUE; break; } - $result = $res_361; - $this->pos = $pos_361; - $key = "Text"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_364 = TRUE; break; + $result = $res_411; + $this->pos = $pos_411; + $_416 = NULL; + do { + $res_413 = $result; + $pos_413 = $this->pos; + $key = "Injection"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_416 = TRUE; break; + } + $result = $res_413; + $this->pos = $pos_413; + $key = "Text"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_416 = TRUE; break; + } + $result = $res_413; + $this->pos = $pos_413; + $_416 = FALSE; break; } - $result = $res_361; - $this->pos = $pos_361; - $_364 = FALSE; break; + while(0); + if( $_416 === TRUE ) { $_418 = TRUE; break; } + $result = $res_411; + $this->pos = $pos_411; + $_418 = FALSE; break; } while(0); - if( $_364 === TRUE ) { $_366 = TRUE; break; } - $result = $res_359; - $this->pos = $pos_359; - $_366 = FALSE; break; + if( $_418 === TRUE ) { $_420 = TRUE; break; } + $result = $res_409; + $this->pos = $pos_409; + $_420 = FALSE; break; } while(0); - if( $_366 === TRUE ) { $_368 = TRUE; break; } - $result = $res_357; - $this->pos = $pos_357; - $_368 = FALSE; break; + if( $_420 === TRUE ) { $_422 = TRUE; break; } + $result = $res_407; + $this->pos = $pos_407; + $_422 = FALSE; break; } while(0); - if( $_368 === TRUE ) { $_370 = TRUE; break; } - $result = $res_355; - $this->pos = $pos_355; - $_370 = FALSE; break; + if( $_422 === TRUE ) { $_424 = TRUE; break; } + $result = $res_405; + $this->pos = $pos_405; + $_424 = FALSE; break; } while(0); - if( $_370 === TRUE ) { $_372 = TRUE; break; } - $result = $res_353; - $this->pos = $pos_353; - $_372 = FALSE; break; + if( $_424 === TRUE ) { $_426 = TRUE; break; } + $result = $res_403; + $this->pos = $pos_403; + $_426 = FALSE; break; } while(0); - if( $_372 === TRUE ) { $_374 = TRUE; break; } - $result = $res_351; - $this->pos = $pos_351; - $_374 = FALSE; break; + if( $_426 === TRUE ) { $_428 = TRUE; break; } + $result = $res_401; + $this->pos = $pos_401; + $_428 = FALSE; break; } while(0); - if( $_374 === TRUE ) { $_376 = TRUE; break; } - $result = $res_349; - $this->pos = $pos_349; - $_376 = FALSE; break; + if( $_428 === TRUE ) { $_430 = TRUE; break; } + $result = $res_399; + $this->pos = $pos_399; + $_430 = FALSE; break; } while(0); - if( $_376 === FALSE) { $_378 = FALSE; break; } - $_378 = TRUE; break; + if( $_430 === FALSE) { $_432 = FALSE; break; } + $_432 = TRUE; break; } while(0); - if( $_378 === FALSE) { - $result = $res_379; - $this->pos = $pos_379; - unset( $res_379 ); - unset( $pos_379 ); + if( $_432 === FALSE) { + $result = $res_433; + $this->pos = $pos_433; + unset( $res_433 ); + unset( $pos_433 ); break; } $count += 1; @@ -2243,173 +2480,191 @@ class SSTemplateParser extends Parser { $res['php'] .= $sub['php'] . PHP_EOL ; } - /* TopTemplate: (Comment | If | Require | ClosedBlock | OpenBlock | MalformedBlock | MismatchedEndBlock | Injection | Text)+ */ + /* TopTemplate: (Comment | If | Require | OldI18NTag | ClosedBlock | OpenBlock | MalformedBlock | MismatchedEndBlock | Injection | Text)+ */ function match_TopTemplate ($substack = array()) { $result = $this->construct( "TopTemplate" ); $count = 0; while (true) { - $res_414 = $result; - $pos_414 = $this->pos; - $_413 = NULL; + $res_472 = $result; + $pos_472 = $this->pos; + $_471 = NULL; do { - $_411 = NULL; + $_469 = NULL; do { - $res_380 = $result; - $pos_380 = $this->pos; + $res_434 = $result; + $pos_434 = $this->pos; $key = "Comment"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comment(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_411 = TRUE; break; + $_469 = TRUE; break; } - $result = $res_380; - $this->pos = $pos_380; - $_409 = NULL; + $result = $res_434; + $this->pos = $pos_434; + $_467 = NULL; do { - $res_382 = $result; - $pos_382 = $this->pos; + $res_436 = $result; + $pos_436 = $this->pos; $key = "If"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_If(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_409 = TRUE; break; + $_467 = TRUE; break; } - $result = $res_382; - $this->pos = $pos_382; - $_407 = NULL; + $result = $res_436; + $this->pos = $pos_436; + $_465 = NULL; do { - $res_384 = $result; - $pos_384 = $this->pos; + $res_438 = $result; + $pos_438 = $this->pos; $key = "Require"; $pos = $this->pos; $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Require(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_407 = TRUE; break; + $_465 = TRUE; break; } - $result = $res_384; - $this->pos = $pos_384; - $_405 = NULL; + $result = $res_438; + $this->pos = $pos_438; + $_463 = NULL; do { - $res_386 = $result; - $pos_386 = $this->pos; - $key = "ClosedBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); + $res_440 = $result; + $pos_440 = $this->pos; + $key = "OldI18NTag"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OldI18NTag(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_405 = TRUE; break; + $_463 = TRUE; break; } - $result = $res_386; - $this->pos = $pos_386; - $_403 = NULL; + $result = $res_440; + $this->pos = $pos_440; + $_461 = NULL; do { - $res_388 = $result; - $pos_388 = $this->pos; - $key = "OpenBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); + $res_442 = $result; + $pos_442 = $this->pos; + $key = "ClosedBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_403 = TRUE; break; + $_461 = TRUE; break; } - $result = $res_388; - $this->pos = $pos_388; - $_401 = NULL; + $result = $res_442; + $this->pos = $pos_442; + $_459 = NULL; do { - $res_390 = $result; - $pos_390 = $this->pos; - $key = "MalformedBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); + $res_444 = $result; + $pos_444 = $this->pos; + $key = "OpenBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_401 = TRUE; break; + $_459 = TRUE; break; } - $result = $res_390; - $this->pos = $pos_390; - $_399 = NULL; + $result = $res_444; + $this->pos = $pos_444; + $_457 = NULL; do { - $res_392 = $result; - $pos_392 = $this->pos; - $key = "MismatchedEndBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MismatchedEndBlock(array_merge($substack, array($result))) ) ); + $res_446 = $result; + $pos_446 = $this->pos; + $key = "MalformedBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_399 = TRUE; break; + $_457 = TRUE; break; } - $result = $res_392; - $this->pos = $pos_392; - $_397 = NULL; + $result = $res_446; + $this->pos = $pos_446; + $_455 = NULL; do { - $res_394 = $result; - $pos_394 = $this->pos; - $key = "Injection"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); + $res_448 = $result; + $pos_448 = $this->pos; + $key = "MismatchedEndBlock"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MismatchedEndBlock(array_merge($substack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_397 = TRUE; break; + $_455 = TRUE; break; } - $result = $res_394; - $this->pos = $pos_394; - $key = "Text"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_397 = TRUE; break; + $result = $res_448; + $this->pos = $pos_448; + $_453 = NULL; + do { + $res_450 = $result; + $pos_450 = $this->pos; + $key = "Injection"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_453 = TRUE; break; + } + $result = $res_450; + $this->pos = $pos_450; + $key = "Text"; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_453 = TRUE; break; + } + $result = $res_450; + $this->pos = $pos_450; + $_453 = FALSE; break; } - $result = $res_394; - $this->pos = $pos_394; - $_397 = FALSE; break; + while(0); + if( $_453 === TRUE ) { $_455 = TRUE; break; } + $result = $res_448; + $this->pos = $pos_448; + $_455 = FALSE; break; } while(0); - if( $_397 === TRUE ) { $_399 = TRUE; break; } - $result = $res_392; - $this->pos = $pos_392; - $_399 = FALSE; break; + if( $_455 === TRUE ) { $_457 = TRUE; break; } + $result = $res_446; + $this->pos = $pos_446; + $_457 = FALSE; break; } while(0); - if( $_399 === TRUE ) { $_401 = TRUE; break; } - $result = $res_390; - $this->pos = $pos_390; - $_401 = FALSE; break; + if( $_457 === TRUE ) { $_459 = TRUE; break; } + $result = $res_444; + $this->pos = $pos_444; + $_459 = FALSE; break; } while(0); - if( $_401 === TRUE ) { $_403 = TRUE; break; } - $result = $res_388; - $this->pos = $pos_388; - $_403 = FALSE; break; + if( $_459 === TRUE ) { $_461 = TRUE; break; } + $result = $res_442; + $this->pos = $pos_442; + $_461 = FALSE; break; } while(0); - if( $_403 === TRUE ) { $_405 = TRUE; break; } - $result = $res_386; - $this->pos = $pos_386; - $_405 = FALSE; break; + if( $_461 === TRUE ) { $_463 = TRUE; break; } + $result = $res_440; + $this->pos = $pos_440; + $_463 = FALSE; break; } while(0); - if( $_405 === TRUE ) { $_407 = TRUE; break; } - $result = $res_384; - $this->pos = $pos_384; - $_407 = FALSE; break; + if( $_463 === TRUE ) { $_465 = TRUE; break; } + $result = $res_438; + $this->pos = $pos_438; + $_465 = FALSE; break; } while(0); - if( $_407 === TRUE ) { $_409 = TRUE; break; } - $result = $res_382; - $this->pos = $pos_382; - $_409 = FALSE; break; + if( $_465 === TRUE ) { $_467 = TRUE; break; } + $result = $res_436; + $this->pos = $pos_436; + $_467 = FALSE; break; } while(0); - if( $_409 === TRUE ) { $_411 = TRUE; break; } - $result = $res_380; - $this->pos = $pos_380; - $_411 = FALSE; break; + if( $_467 === TRUE ) { $_469 = TRUE; break; } + $result = $res_434; + $this->pos = $pos_434; + $_469 = FALSE; break; } while(0); - if( $_411 === FALSE) { $_413 = FALSE; break; } - $_413 = TRUE; break; + if( $_469 === FALSE) { $_471 = FALSE; break; } + $_471 = TRUE; break; } while(0); - if( $_413 === FALSE) { - $result = $res_414; - $this->pos = $pos_414; - unset( $res_414 ); - unset( $pos_414 ); + if( $_471 === FALSE) { + $result = $res_472; + $this->pos = $pos_472; + unset( $res_472 ); + unset( $pos_472 ); break; } $count += 1; diff --git a/core/SSTemplateParser.php.inc b/core/SSTemplateParser.php.inc index cc5d28a1c..56c09d704 100644 --- a/core/SSTemplateParser.php.inc +++ b/core/SSTemplateParser.php.inc @@ -228,7 +228,7 @@ class SSTemplateParser extends Parser { function Argument_QuotedString(&$res, $sub) { $res['ArgumentMode'] = 'string'; - $res['php'] = "'" . $sub['String']['text'] . "'"; + $res['php'] = "'" . str_replace("'", "\\'", $sub['String']['text']) . "'"; } function Argument_Lookup(&$res, $sub) { @@ -245,7 +245,7 @@ class SSTemplateParser extends Parser { function Argument_FreeString(&$res, $sub) { $res['ArgumentMode'] = 'string'; - $res['php'] = "'" . $sub['text'] . "'"; + $res['php'] = "'" . str_replace("'", "\\'", $sub['text']) . "'"; } /*!* @@ -374,6 +374,80 @@ class SSTemplateParser extends Parser { function Require_Call(&$res, $sub) { $res['php'] = "Requirements::".$sub['Method']['text'].'('.$sub['CallArguments']['php'].');'; } + + /*!* + + # Deprecated old-style i18n _t and sprintf(_t block tags. We support a slightly more flexible version than we used + # to, but just because it's easier to do so. It's strongly recommended to use the new syntax + + # This is the core used by both syntaxes, without the block start & end tags + + OldTPart: "_t" < "(" < QuotedString (< "," < CallArguments)? > ")" + + */ + function OldTPart__construct(&$res) { + $res['php'] = "_t("; + } + + function OldTPart_QuotedString(&$res, $sub) { + $entity = $sub['String']['text']; + if (strpos($entity, '.') === false) { + $res['php'] .= "\$scope->XML_val('I18NNamespace').'.$entity'"; + } + else { + $res['php'] .= "'$entity'"; + } + } + + function OldTPart_CallArguments(&$res, $sub) { + $res['php'] .= ',' . $sub['php']; + } + + function OldTPart__finalise(&$res) { + $res['php'] .= ')'; + } + + /*!* + + # This is the old <% _t() %> tag + + OldTTag: "<%" < OldTPart > "%>" + + */ + function OldTTag_OldTPart(&$res, $sub) { + $res['php'] = $sub['php']; + } + + /*!* + + # This is the old <% sprintf(_t()) %> tag + + OldSprintfTag: "<%" < "sprintf" < "(" < OldTPart < "," < CallArguments > ")" > "%>" + + */ + function OldSprintfTag__construct(&$res) { + $res['php'] = "sprintf("; + } + + function OldSprintfTag_OldTPart(&$res, $sub) { + $res['php'] .= $sub['php']; + } + + function OldSprintfTag_CallArguments(&$res, $sub) { + $res['php'] .= ',' . $sub['php'] . ')'; + } + + /*!* + + # This matches either the old style sprintf(_t()) or _t() tags. As well as including the output portion of the + # php, this rule combines all the old i18n stuff into a single match rule to make it easy to not support these tags later + + OldI18NTag: OldSprintfTag | OldTTag + + */ + function OldI18NTag_STR(&$res, $sub) { + $res['php'] = '$val .= ' . $sub['php'] . ';'; + } /*!* @@ -641,7 +715,7 @@ class SSTemplateParser extends Parser { # Template is any structurally-complete portion of template (a full nested level in other words). It's used # by the block rules to recurse - Template: (Comment | If | Require | ClosedBlock | OpenBlock | MalformedBlock | Injection | Text)+ + Template: (Comment | If | Require | OldI18NTag | ClosedBlock | OpenBlock | MalformedBlock | Injection | Text)+ */ function Template__construct(&$res) { $res['php'] = ''; @@ -673,7 +747,7 @@ class SSTemplateParser extends Parser { # TopTemplate is the same as Template, but should only be used at the top level (not nested), as it includes # MismatchedEndBlock detection, which only works at the top level - TopTemplate: (Comment | If | Require | ClosedBlock | OpenBlock | MalformedBlock | MismatchedEndBlock | Injection | Text)+ + TopTemplate: (Comment | If | Require | OldI18NTag | ClosedBlock | OpenBlock | MalformedBlock | MismatchedEndBlock | Injection | Text)+ */ /** diff --git a/core/SSViewer.php b/core/SSViewer.php index 379e896bc..0f40795ed 100755 --- a/core/SSViewer.php +++ b/core/SSViewer.php @@ -20,7 +20,7 @@ * and revert back to the original scope once we've got the value we're after * */ -class SSViewer_DataPresenter { +class SSViewer_Scope { // The stack of previous "global" items // And array of item, itemIterator, pop_index, up_index, current_index @@ -124,6 +124,44 @@ class SSViewer_DataPresenter { } } +/** + * This extends SSViewer_Scope to mix in data on top of what the item provides. This can be "global" + * data that is scope-independant (like BaseURL), or type-specific data that is layered on top cross-cut like + * (like $FirstLast etc). + * + * It's separate from SSViewer_Scope to keep that fairly complex code as clean as possible. + */ +class SSViewer_DataPresenter extends SSViewer_Scope { + + private $extras; + + function __construct($item, $extras = null){ + parent::__construct($item); + $this->extras = $extras; + } + + function __call($name, $arguments) { + $property = $arguments[0]; + + if ($this->extras && array_key_exists($property, $this->extras)) { + + $this->resetLocalScope(); + + $value = $this->extras[$arguments[0]]; + + switch ($name) { + case 'hasValue': + return (bool)$value; + default: + return $value; + } + } + + return parent::__call($name, $arguments); + } +} + + /** * Parses a template file with an *.ss file extension. * @@ -547,7 +585,7 @@ class SSViewer { } } - $scope = new SSViewer_DataPresenter($item); + $scope = new SSViewer_DataPresenter($item, array('I18NNamespace' => basename($template))); $val = ""; $valStack = array(); include($cacheFile); From fdf81c80cb96ebc34a54750727d0fc56d54768fd Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Thu, 10 Mar 2011 12:00:49 +1300 Subject: [PATCH 12/15] MINOR: Pull in latest changes from thirdparty tool php-peg --- thirdparty/php-peg/.piston.yml | 4 +- thirdparty/php-peg/Compiler.php | 331 ++++++++++++------ thirdparty/php-peg/Parser.php | 143 +++----- thirdparty/php-peg/README.md | 155 ++++++-- .../php-peg/tests/ParserInheritanceTest.php | 123 +++++++ thirdparty/php-peg/tests/ParserSyntaxTest.php | 26 ++ thirdparty/php-peg/tests/ParserTestBase.php | 48 +++ .../php-peg/tests/ParserVariablesTest.php | 55 +++ 8 files changed, 652 insertions(+), 233 deletions(-) create mode 100644 thirdparty/php-peg/tests/ParserInheritanceTest.php create mode 100644 thirdparty/php-peg/tests/ParserSyntaxTest.php create mode 100644 thirdparty/php-peg/tests/ParserTestBase.php create mode 100644 thirdparty/php-peg/tests/ParserVariablesTest.php diff --git a/thirdparty/php-peg/.piston.yml b/thirdparty/php-peg/.piston.yml index 0ecfabf6b..7b02f2e63 100644 --- a/thirdparty/php-peg/.piston.yml +++ b/thirdparty/php-peg/.piston.yml @@ -1,9 +1,9 @@ --- format: 1 handler: - commit: afb28caf712815da82cd6bb8ece8ac12ab9b2188 + commit: 2045d5fbfa3ed857a9eac3722e6f9ecc301593c6 branch: master lock: false repository_class: Piston::Git::Repository repository_url: git://github.com/hafriedlander/php-peg.git -exported_to: 0669b742904f8c9f7cd97569166663396897dab9 +exported_to: 654df253d884db2cd397016de1a5105455ba1631 diff --git a/thirdparty/php-peg/Compiler.php b/thirdparty/php-peg/Compiler.php index 2acd72dae..5d34482c2 100644 --- a/thirdparty/php-peg/Compiler.php +++ b/thirdparty/php-peg/Compiler.php @@ -215,22 +215,19 @@ abstract class Token extends PHPWriter { } if ( $this->tag && !($this instanceof TokenRecurse ) ) { - $rid = $this->varid() ; $code = PHPBuilder::build() ->l( - '$substack[] = $result;', - '$result = $this->construct( "'.$this->tag.'" );', + '$stack[] = $result; $result = $this->construct( $matchrule, "'.$this->tag.'" ); ', $code->replace(array( 'MATCH' => PHPBuilder::build() ->l( - '$subres = $result ;', - '$result = array_pop( $substack ) ;', + '$subres = $result; $result = array_pop($stack);', '$this->store( $result, $subres, \''.$this->tag.'\' );', 'MATCH' ), 'FAIL' => PHPBuilder::build() ->l( - '$result = array_pop( $substack ) ;', + '$result = array_pop($stack);', 'FAIL' ) ))); @@ -255,31 +252,30 @@ abstract class TokenTerminal extends Token { abstract class TokenExpressionable extends TokenTerminal { - static $expression_rx = '/\$(\w+)/' ; + static $expression_rx = '/ \$(\w+) | { \$(\w+) } /x'; function contains_expression(){ return preg_match(self::$expression_rx, $this->value); } + function expression_replace($matches) { + return '\'.$this->expression($result, $stack, \'' . (!empty($matches[1]) ? $matches[1] : $matches[2]) . "').'"; + } + function match_code( $value ) { - if (!$this->contains_expression()) parent::match_code($value); - - $id = $this->varid() ; - return PHPBuilder::build()->l( - '$'.$id.' = new ParserExpression( $this, $substack, $result );', - parent::match_code('$'.$id.'->expand('.$value.')') - ); + $value = preg_replace_callback(self::$expression_rx, array($this, 'expression_replace'), $value); + return parent::match_code($value); } } class TokenLiteral extends TokenExpressionable { function __construct( $value ) { - parent::__construct( 'literal', $value ); + parent::__construct( 'literal', "'" . substr($value,1,-1) . "'" ); } function match_code() { // We inline single-character matches for speed - if ( strlen( eval( 'return '. $this->value . ';' ) ) == 1 ) { + if ( !$this->contains_expression() && strlen( eval( 'return '. $this->value . ';' ) ) == 1 ) { return $this->match_fail_conditional( 'substr($this->string,$this->pos,1) == '.$this->value, PHPBuilder::build()->l( '$this->pos += 1;', @@ -319,37 +315,18 @@ class TokenWhitespace extends TokenTerminal { } } -class TokenPHP extends TokenTerminal { - function __construct( $value ) { - parent::__construct( 'php', $value ) ; - } - - /* Call recursion indirectly */ - function match_code() { - $id = $this->varid() ; - return PHPBuilder::build() - ->l( - '$'.$id.' = new ParserExpression( $this, $substack, $result );', - $this->match_fail_block( '( $subres = $'.$id.'->match( \''.$this->value.'\' ) ) !== FALSE', - PHPBuilder::build() - ->b( 'if ( is_string( $subres ) )', - $this->set_text('$subres') - ) - ->b( 'else', - '$this->store($result, $subres);' - ) - )); - } -} - class TokenRecurse extends Token { function __construct( $value ) { parent::__construct( 'recurse', $value ) ; } + function match_function() { + return "'".$this->function_name($this->value)."'"; + } + function match_code() { - $function = $this->function_name( $this->value ) ; - $storetag = $this->function_name( $this->tag ? $this->tag : $this->value ) ; + $function = $this->match_function() ; + $storetag = $this->function_name( $this->tag ? $this->tag : $this->match_function() ) ; if ( ParserCompiler::$debug ) { $debug_header = PHPBuilder::build() @@ -358,7 +335,7 @@ class TokenRecurse extends Token { '$this->depth += 2;', '$sub = ( strlen( $this->string ) - $this->pos > 20 ) ? ( substr( $this->string, $this->pos, 20 ) . "..." ) : substr( $this->string, $this->pos );', '$sub = preg_replace( \'/(\r|\n)+/\', " {NL} ", $sub );', - 'print( $indent."Matching against '.$function.' (".$sub.")\n" );' + 'print( $indent."Matching against $matcher (".$sub.")\n" );' ); $debug_match = PHPBuilder::build() @@ -378,9 +355,9 @@ class TokenRecurse extends Token { } return PHPBuilder::build()->l( + '$matcher = \'match_\'.'.$function.'; $key = $matcher; $pos = $this->pos;', $debug_header, - '$key = "'.$function.'"; $pos = $this->pos;', // :{$this->pos}";', - '$subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_'.$function.'(array_merge($substack, array($result))) ) );', + '$subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );', $this->match_fail_conditional( '$subres !== FALSE', PHPBuilder::build()->l( $debug_match, @@ -395,6 +372,12 @@ class TokenRecurse extends Token { } } +class TokenExpressionedRecurse extends TokenRecurse { + function match_function() { + return '$this->expression($result, $stack, \''.$this->value.'\')'; + } +} + class TokenSequence extends Token { function __construct( $value ) { parent::__construct( 'sequence', $value ) ; @@ -479,40 +462,115 @@ class Pending { */ class Rule extends PHPWriter { - static $rule_rx = '@^[\x20\t]+(.*)@' ; - static $func_rx = '@^[\x20\t]+function\s+([^\s(]+)\s*\(([^)]*)\)@' ; + static $rule_rx = '@ + (? \w+) # The name of the rule + ( \s+ extends \s+ (?\w+) )? # The extends word + ( \s* \( (?.*) \) )? # Any variable setters + ( + \s*(?:) | # Marks the matching rule start + \s*(?;) | # Marks the replacing rule start + \s*$ + ) + (?[\s\S]*) + @x'; - function __construct( $indent, $rules, $match ) { - $this->indent = $indent; - $this->name = $match[1][0] ; - $this->rule = $match[2][0] ; + static $argument_rx = '@ + ( [^=]+ ) # Name + = # Seperator + ( [^=,]+ ) # Variable + (,|$) + @x'; + + static $replacement_rx = '@ + ( ([^=]|=[^>])+ ) # What to replace + => # The replacement mark + ( [^,]+ ) # What to replace it with + (,|$) + @x'; + + static $function_rx = '@^\s+function\s+([^\s(]+)\s*(.*)@' ; + + protected $parser; + protected $lines; + + public $name; + public $extends; + public $mode; + public $rule; + + function __construct($parser, $lines) { + $this->parser = $parser; + $this->lines = $lines; + + // Find the first line (if any) that's an attached function definition. Can skip first line (unless this block is malformed) + for ($i = 1; $i < count($lines); $i++) { + if (preg_match(self::$function_rx, $lines[$i])) break; + } + + // Then split into the two parts + $spec = array_slice($lines, 0, $i); + $funcs = array_slice($lines, $i); + + // Parse out the spec + $spec = implode("\n", $spec); + if (!preg_match(self::$rule_rx, $spec, $specmatch)) user_error('Malformed rule spec ' . $spec, E_USER_ERROR); + + $this->name = $specmatch['name']; + + if ($specmatch['extends']) { + $this->extends = $this->parser->rules[$specmatch['extends']]; + if (!$this->extends) user_error('Extended rule '.$specmatch['extends'].' is not defined before being extended', E_USER_ERROR); + } + + $this->arguments = array(); + + if ($specmatch['arguments']) { + preg_match_all(self::$argument_rx, $specmatch['arguments'], $arguments, PREG_SET_ORDER); + + foreach ($arguments as $argument){ + $this->arguments[trim($argument[1])] = trim($argument[2]); + } + } + + $this->mode = $specmatch['matchmark'] ? 'rule' : 'replace'; + + if ($this->mode == 'rule') { + $this->rule = $specmatch['rule']; + $this->parse_rule() ; + } + else { + if (!$this->extends) user_error('Replace matcher, but not on an extends rule', E_USER_ERROR); + + $this->replacements = array(); + preg_match_all(self::$replacement_rx, $specmatch['rule'], $replacements, PREG_SET_ORDER); + + $rule = $this->extends->rule; + + foreach ($replacements as $replacement) { + $search = trim($replacement[1]); + $replace = trim($replacement[3]); if ($replace == "''" || $replace == '""') $replace = ""; + + $rule = str_replace($search, ' '.$replace.' ', $rule); + } + + $this->rule = $rule; + $this->parse_rule() ; + } + + // Parse out the functions + $this->functions = array() ; $active_function = NULL ; - /* Find all the lines following the rule start which are indented */ - $offset = $match[0][1] + strlen( $match[0][0] ) ; - $lines = preg_split( '/\r\n|\r|\n/', substr( $rules, $offset ) ) ; - - $rule_rx = '@^'.preg_quote($indent).'[\x20\t]+(.*)@' ; - $func_rx = '@^'.preg_quote($indent).'[\x20\t]+function\s+([^\s(]+)\s*\(([^)]*)\)@' ; - - foreach( $lines as $line ) { - if ( !trim( $line ) ) continue ; - if ( !preg_match( $rule_rx, $line, $match ) ) break ; - + foreach( $funcs as $line ) { /* Handle function definitions */ - if ( preg_match( $func_rx, $line, $func_match, 0 ) ) { - $active_function = $func_match[1] ; - $this->functions[$active_function] = array( $func_match[2], "" ) ; - } - else { - if ( $active_function ) $this->functions[$active_function][1] .= $line . PHP_EOL ; - else $this->rule .= PHP_EOL . trim($line) ; + if ( preg_match( self::$function_rx, $line, $func_match, 0 ) ) { + $active_function = $func_match[1]; + $this->functions[$active_function] = $func_match[2] . PHP_EOL; } + else $this->functions[$active_function] .= $line . PHP_EOL ; } - - $this->parse_rule() ; } /* Manual parsing, because we can't bootstrap ourselves yet */ @@ -528,6 +586,7 @@ class Rule extends PHPWriter { $this->tokenize( $rule, $tokens ) ; $this->parsed = ( count( $tokens ) == 1 ? array_pop( $tokens ) : new TokenSequence( $tokens ) ) ; } + } static $rx_rx = '{^/( @@ -574,7 +633,7 @@ class Rule extends PHPWriter { } /* Handle $ call literals */ elseif ( preg_match( '/^\$(\w+)/', $sub, $match ) ) { - $tokens[] = $t = new TokenPHP( $match[1] ) ; $pending->apply_if_present( $t ) ; + $tokens[] = $t = new TokenExpressionedRecurse( $match[1] ) ; $pending->apply_if_present( $t ) ; $o += strlen( $match[0] ) ; } /* Handle flags */ @@ -652,46 +711,105 @@ class Rule extends PHPWriter { /** * Generate the PHP code for a function to match against a string for this rule */ - function compile() { + function compile($indent) { $function_name = $this->function_name( $this->name ) ; + + // Build the typestack + $typestack = array(); $class=$this; + do { + $typestack[] = $this->function_name($class->name); + } + while($class = $class->extends); - $match = PHPBuilder::build() ; - - if ( $this->parsed instanceof TokenRegex ) { - $match->b( "function match_{$function_name} (\$substack = array())", - '$result = array("name"=>"'.$function_name.'", "text"=>"");', - $this->parsed->compile()->replace(array( - 'MATCH' => 'return $result;', - 'FAIL' => 'return FALSE;' - )) - ); + $typestack = "array('" . implode("','", $typestack) . "')"; + + // Build an array of additional arguments to add to result node (if any) + if (empty($this->arguments)) { + $arguments = 'null'; } else { - $match->b( "function match_{$function_name} (\$substack = array())", - '$result = $this->construct( "'.$function_name.'" );', - $this->parsed->compile()->replace(array( - 'MATCH' => 'return $this->finalise( "'.$function_name.'", $result );', - 'FAIL' => 'return FALSE;' - )) - ); + $arguments = "array("; + foreach ($this->arguments as $k=>$v) { $arguments .= "'$k' => '$v'"; } + $arguments .= ")"; } + + $match = PHPBuilder::build() ; + + $match->l("protected \$match_{$function_name}_typestack = $typestack;"); + + $match->b( "function match_{$function_name} (\$stack = array())", + '$matchrule = "'.$function_name.'"; $result = $this->construct($matchrule, $matchrule, '.$arguments.');', + $this->parsed->compile()->replace(array( + 'MATCH' => 'return $this->finalise($result);', + 'FAIL' => 'return FALSE;' + )) + ); $functions = array() ; foreach( $this->functions as $name => $function ) { $function_name = $this->function_name( preg_match( '/^_/', $name ) ? $this->name.$name : $this->name.'_'.$name ) ; $functions[] = implode( PHP_EOL, array( - 'function ' . $function_name . ' ( ' . $function[0] . ' ) { ', - $function[1], + 'function ' . $function_name . ' ' . $function )); } // print_r( $match ) ; return '' ; - return $match->render(NULL, $this->indent) . PHP_EOL . PHP_EOL . implode( PHP_EOL, $functions ) ; + return $match->render(NULL, $indent) . PHP_EOL . PHP_EOL . implode( PHP_EOL, $functions ) ; + } +} + +class RuleSet { + public $rules = array(); + + function addRule($indent, $lines, &$out) { + $rule = new Rule($this, $lines) ; + $this->rules[$rule->name] = $rule; + + $out[] = $indent . '/* ' . $rule->name . ':' . $rule->rule . ' */' . PHP_EOL ; + $out[] = $rule->compile($indent) ; + $out[] = PHP_EOL ; + } + + function compile($indent, $rulestr) { + $indentrx = '@^'.preg_quote($indent).'@'; + + $out = array(); + $block = array(); + + foreach (preg_split('/\r\n|\r|\n/', $rulestr) as $line) { + // Ignore blank lines + if (!trim($line)) continue; + // Ignore comments + if (preg_match('/^[\x20|\t]+#/', $line)) continue; + + // Strip off indent + if (!empty($indent)) { + if (strpos($line, $indent) === 0) $line = substr($line, strlen($indent)); + else user_error('Non-blank line with inconsistent index in parser block', E_USER_ERROR); + } + + // Any indented line, add to current set of lines + if (preg_match('/^\x20|\t/', $line)) $block[] = $line; + + // Any non-indented line marks a new block. Add a rule for the current block, then start a new block + else { + if (count($block)) $this->addRule($indent, $block, $out); + $block = array($line); + } + } + + // Any unfinished block add a rule for + if (count($block)) $this->addRule($indent, $block, $out); + + // And return the compiled version + return implode( '', $out ) ; } } class ParserCompiler { + static $parsers = array(); + static $debug = false; static $currentClass = null; @@ -700,17 +818,11 @@ class ParserCompiler { /* We allow indenting of the whole rule block, but only to the level of the comment start's indent */ $indent = $match[1]; - /* The regex to match a rule */ - $rx = '@^'.preg_quote($indent).'([\w\-]+):(.*)$@m' ; - - /* Class isn't actually used ATM. Eventually it might be used for rule inlineing optimization */ + /* Get the parser name for this block */ if ($class = trim($match[2])) self::$currentClass = $class; elseif (self::$currentClass) $class = self::$currentClass; else $class = self::$currentClass = 'Anonymous Parser'; - /* Get the actual body of the parser rule set */ - $rulestr = $match[3] ; - /* Check for pragmas */ if (strpos($class, '!') === 0) { switch ($class) { @@ -718,7 +830,7 @@ class ParserCompiler { // NOP - dont output return ''; case '!insert_autogen_warning': - return $ident . implode(PHP_EOL.$ident, array( + return $indent . implode(PHP_EOL.$indent, array( '/*', 'WARNING: This file has been machine generated. Do not edit it, or your changes will be overwritten next time it is compiled.', '*/' @@ -731,22 +843,9 @@ class ParserCompiler { throw new Exception("Unknown pragma $class encountered when compiling parser"); } - $rules = array(); - - preg_match_all( $rx, $rulestr, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE ) ; - foreach ( $matches as $match ) { - $rules[] = new Rule( $indent, $rulestr, $match ) ; - } - - $out = array() ; - - foreach ( $rules as $rule ) { - $out[] = $indent . '/* ' . $rule->name . ':' . $rule->rule . ' */' . PHP_EOL ; - $out[] = $rule->compile() ; - $out[] = PHP_EOL ; - } - - return implode( '', $out ) ; + if (!isset(self::$parsers[$class])) self::$parsers[$class] = new RuleSet(); + + return self::$parsers[$class]->compile($indent, $match[3]); } static function compile( $string ) { diff --git a/thirdparty/php-peg/Parser.php b/thirdparty/php-peg/Parser.php index acae096c8..364f00e93 100644 --- a/thirdparty/php-peg/Parser.php +++ b/thirdparty/php-peg/Parser.php @@ -1,59 +1,5 @@ parser = $parser ; - $this->substack = $substack ; - $this->result = $result ; - } - - function find( $exp ) { - $rule_callback = array( $this->parser, "{$this->result['name']}_DLR{$exp}" ) ; - $pars_callback = array( $this->parser, "DLR{$exp}" ) ; - - /* If the current result has that expression, return it */ - if ( isset( $this->result[$exp] ) ) return $this->result[$exp] ; - - /* Search backwards through the sub-expression stacks */ - for ( $i = count( $this->substack ) - 1 ; $i >= 0 ; $i-- ) { - if ( isset( $this->substack[$i][$exp] ) ) return $this->substack[$i][$exp] ; - } - - /* If we have a rule-attached method, call that */ - if ( is_callable( $rule_callback ) ) return call_user_func( $rule_callback, $result ) ; - - /* If we have a class-wide method, call that */ - if ( is_callable( $pars_callback ) ) return call_user_func( $pars_callback, $result ) ; - - /* If we have a global function, call that */ - if ( function_exists( $exp ) ) return call_user_func( $exp, $result ) ; - - /* If we have a global constant, call that */ - if ( defined( $exp ) ) return constant( $expression ) ; - - return FALSE ; - } - - function callback( $m ) { - $res = $this->find( $m[1] ) ; - if ( $res === FALSE ) return "" ; - if ( is_string( $res ) ) return $res ; - if ( isset( $res['text'] ) ) return $res['text'] ; - - // If we find no matches, assume we don't want a replacement, and replace it with itself - return $m[0] ; - } - - function expand( $var ) { - return preg_replace_callback( '/\$(\w+)/', array( $this, 'callback' ), $var ) ; - } - - function match( $var ) { - return $this->find( $var ) ; - } -} - /** * We cache the last regex result. This is a low-cost optimization, because we have to do an un-anchored match + check match position anyway * (alternative is to do an anchored match on a string cut with substr, but that is very slow for long strings). We then don't need to recheck @@ -133,23 +79,27 @@ class Parser { return $this->regexps[$rx]->match() ; } - function expand( $var, $substack, $result ) { - $cb = new Parser_ExpressionCallback( $this, $substack, $result ) ; - $v = preg_replace_callback( '/\$(\w+)/', array( $cb, 'callback' ), $var ) ; - print "Expanded var: $v" ; - return $v ; - } - - function php( $var, $substack, $result ) { - $ex = $this->get_expression( $var, $substack, $result ) ; - print_r( $result ) ; - - if ( is_string( $ex ) ) { - return ( preg_match( '{^\s*/}', $ex ) ? $this->rx( $ex ) : $this->literal( $ex ) ) ; + function expression( $result, $stack, $value ) { + $stack[] = $result; $rv = false; + + /* Search backwards through the sub-expression stacks */ + for ( $i = count($stack) - 1 ; $i >= 0 ; $i-- ) { + $node = $stack[$i]; + + if ( isset($node[$value]) ) { $rv = $node[$value]; break; } + + foreach ($this->typestack($node['_matchrule']) as $type) { + $callback = array($this, "{$type}_DLR{$value}"); + if ( is_callable( $callback ) ) { $rv = call_user_func( $callback ) ; if ($rv !== FALSE) break; } + } } - return $ex ; - } + if ($rv === false) $rv = @$this->$value; + if ($rv === false) $rv = @$this->$value(); + + return is_array($rv) ? $rv['text'] : ($rv ? $rv : ''); + } + function packhas( $key, $pos ) { return false ; } @@ -162,21 +112,33 @@ class Parser { return $res ; } - function construct( $name ) { - $result = array( 'type' => 'node', 'name' => $name, 'text' => '' ) ; + function typestack( $name ) { + $prop = "match_{$name}_typestack"; + return $this->$prop; + } + + function construct( $matchrule, $name, $arguments = null ) { + $result = array( '_matchrule' => $matchrule, 'name' => $name, 'text' => '' ); + if ($arguments) $result = array_merge($result, $arguments) ; - $callback = array( $this, "{$name}__construct" ) ; - if ( is_callable( $callback ) ) { - call_user_func_array( $callback, array( &$result ) ) ; + foreach ($this->typestack($matchrule) as $type) { + $callback = array( $this, "{$type}__construct" ) ; + if ( is_callable( $callback ) ) { + call_user_func_array( $callback, array( &$result ) ) ; + break; + } } return $result ; } - function finalise( $name, &$result ) { - $callback = array( $this, "{$name}__finalise" ) ; - if ( is_callable( $callback ) ) { - call_user_func_array( $callback, array( &$result ) ) ; + function finalise( &$result ) { + foreach ($this->typestack($result['_matchrule']) as $type) { + $callback = array( $this, "{$type}__finalise" ) ; + if ( is_callable( $callback ) ) { + call_user_func_array( $callback, array( &$result ) ) ; + break; + } } return $result ; @@ -185,16 +147,23 @@ class Parser { function store ( &$result, $subres, $storetag = NULL ) { $result['text'] .= $subres['text'] ; - $globalcb = array( $this, "{$result['name']}_STR" ) ; - $callback = array( $this, $storetag ? "{$result['name']}_{$storetag}" : "{$result['name']}_{$subres['name']}" ) ; + $storecalled = false; - if ( is_callable( $callback ) ) { - call_user_func_array( $callback, array( &$result, $subres ) ) ; - } - elseif ( is_callable( $globalcb ) ) { - call_user_func_array( $globalcb, array( &$result, $subres ) ) ; - } - elseif ( $storetag ) { + foreach ($this->typestack($result['_matchrule']) as $type) { + $callback = array( $this, $storetag ? "{$type}_{$storetag}" : "{$type}_{$subres['name']}" ) ; + if ( is_callable( $callback ) ) { + call_user_func_array( $callback, array( &$result, $subres ) ) ; + $storecalled = true; break; + } + + $globalcb = array( $this, "{$type}_STR" ) ; + if ( is_callable( $globalcb ) ) { + call_user_func_array( $globalcb, array( &$result, $subres ) ) ; + $storecalled = true; break; + } + } + + if ( $storetag && !$storecalled ) { if ( !isset( $result[$storetag] ) ) $result[$storetag] = $subres ; else { if ( isset( $result[$storetag]['text'] ) ) $result[$storetag] = array( $result[$storetag] ) ; diff --git a/thirdparty/php-peg/README.md b/thirdparty/php-peg/README.md index d327dc2f2..807b3b73d 100644 --- a/thirdparty/php-peg/README.md +++ b/thirdparty/php-peg/README.md @@ -19,9 +19,6 @@ and lexing in a single top down grammar. For a basic overview of the subject, se Parsers are contained within a PHP file, in one or more special comment blocks that start with `/*!* [name | !pragma]` (like a docblock, but with an exclamation mark in the middle of the stars) -Lexically, these blocks are a set of rules, each consisting of a name token, a matching rule and a set of attached functions. -The name token must contain no whitespace and end with a `:` character. The matching rule and functions are on the same line or on the indented lines below. - You can have multiple comment blocks, all of which are treated as contiguous for the purpose of compiling. During compilation these blocks will be replaced with a set of "matching" functions (functions which match a string against their rules) for each rule in the block. @@ -30,6 +27,30 @@ If unspecified, it defaults to the same name as the previous parser comment bloc If the name starts with an '!' symbol, that comment block is a pragma, and is treated not as some part of the parser, but as a special block of meta-data +Lexically, these blocks are a set of rules & comments. A rule can be a base rule or an extension rule + +##### Base rules + +Base rules consist of a name for the rule, some optional arguments, the matching rule itself, and an optional set of attached functions + +NAME ( "(" ARGUMENT, ... ")" )? ":" MATCHING_RULE + ATTACHED_FUNCTIONS? + +Names must be the characters a-z, A-Z, 0-9 and _ only, and must not start with a number + +Base rules can be split over multiple lines as long as subsequent lines are indented + +##### Extension rules + +Extension rules are either the same as a base rule but with an addition name of the rule to extend, or as a replacing extension consist of +a name for the rule, the name of the rule to extend, and optionally: some arguments, some replacements, and a set of attached functions + +NAME extend BASENAME ( "(" ARGUMENT, ... ")" )? ":" MATCHING_RULE + ATTACHED_FUNCTIONS? + +NAME extends BASENAME ( "(" ARGUMENT, ... ")" )? ( ";" REPLACE "=>" REPLACE_WITH, ... )? + ATTACHED_FUNCTIONS? + ##### Tricks and traps We allow indenting a parser block, but only in a consistant manner - whatever the indent of the /*** marker becomes the "base" indent, and needs to be used @@ -46,7 +67,7 @@ This might get looser if I get around to re-writing the internal "parser parser" PEG matching rules try to follow standard PEG format, summarised thusly: -
+

 	token* - Token is optionally repeated
 	token+ - Token is repeated at least one
 	token? - Token is optionally present
@@ -62,7 +83,7 @@ PEG matching rules try to follow standard PEG format, summarised thusly:
 
 But with these extensions:
 
-
+

 	< or > - Optionally match whitespace
 	[ or ] - Require some whitespace
 
@@ -87,32 +108,56 @@ just split with a space (as in / foo \s* /) ### Expressions Expressions allow run-time calculated matching. You can embed an expression within a literal or regex token to -match against a calculated value, or simply specify the expression as a token to (optionally) internally handle matching -and generate a result. +match against a calculated value, or simply specify the expression as a token to match against a dynamic rule. -Expressions will try a variety of scopes to find a value. It will look for variables already set in the current result, -rule-attached functions and a variety of other functions and constants. +#### Expression stack -Tried in this order +When getting a value to use for an expression, the parser will travel up the stack looking for a set value. The expression +stack is a list of all the rules passed through to get to this point. For example, given the parser -- against current result -- against containing expression stack in order (for sub-expressions only) - - against parser instance as variable - - against parser instance as rule-attached method INCLUDING `$` ( i.e. `function $foo()` ) - - against parser instance as method INCLUDING `$` - - as global method -- as constant +

+	A: $a
+	B: A
+	C: B
+
+ +The expression stack for finding $a will be C, B, A - in other words, the A rule will be checked first, followed by B, followed by C -##### Tricks and traps +#### In terminals (literals and regexes) -Be careful against matching against results +The token will be replaced by the looked up value. To find the value for the token, the expression stack will be +travelled up checking for one of the following: + + - A key / value pair in the result array node + - A rule-attached method INCLUDING `$` ( i.e. `function $foo()` ) + +If no value is found it will then check if a method or a property excluding the $ exists on the parser. If neither of those is found +the expression will be replaced with an exmpty string/ + +#### As tokens + +The token will be looked up to find a value, which must be the name of a matching rule. That rule will then be matched +against as if the token was a recurse token for that rule. + +To find the name of the rule to match against, the expression stack will be travelled up checking for one of the following: + + - A key / value pair in the result array node + - A rule-attached method INCLUDING `$` ( i.e. `function $foo()` ) + +If no value is found it will then check if a method or a property excluding the $ exists on the parser. If neither of those if found +the rule will fail to match. + +#### Tricks and traps + +Be careful against using a token expression when you meant to use a terminal expression

 	quoted_good: q:/['"]/ string "$q"
 	quoted_bad:  q:/['"]/ string $q
 
-`"$q"` matches against the value of q again. `$q` simply returns the value of q, without doing any matching +`"$q"` matches against the value of q again. `$q` tries to match against a rule named `"` or `'` (both of which are illegal rule +names, and will therefore fail) ### Named matching rules @@ -149,16 +194,16 @@ All these definitions define the same rule-attached function

 	class A extends Parser {
-	/**Parser
-	foo: bar baz
-	  function bar() {}
-	* /
+		/*!* Parser
+		foo: bar baz
+			function bar() {}
+		*/
 
-	  function foo_bar() {}
+		function foo_bar() {}
 	}
 
 	class B extends A {
-	  function foo_bar() {}
+		function foo_bar() {}
 	}
 
@@ -206,6 +251,62 @@ You can also specify a rule-attached function called `*`, which will be called w By default all matches are added to the 'text' property of a result. By prepending a member with `.` that match will not be added to the ['text'] member. This doesn't affect the other result properties that named rules' add. +### Inheritance + +Rules can inherit off other rules using the keyword extends. There are several ways to change the matching of the rule, but +they all share a common feature - when building a result set the rule will also check the inherited-from rule's rule-attached +functions for storage handlers. This lets you do something like + +

+A: Foo Bar Baz
+  function *(){ /* Generic store handler */ }
+  
+B extends A
+  function Bar(){ /* Custom handling for Bar - Foo and Baz will still fall through to the A#* function defined above */ }
+
+ +The actual matching rule can be specified in three ways: + +#### Duplication + +If you don't specify a new rule or a replacement set the matching rule is copied as is. This is useful when you want to +override some storage logic but not the rule itself + +#### Text replacement + +You can replace some parts of the inherited rule using test replacement by using a ';' instead of an ':' after the name + of the extended rule. You can then put replacements in a comma seperated list. An example might help + +

+A: Foo | Bar | Baz
+
+# Makes B the equivalent of Foo | Bar | (Baz | Qux)
+B extends A: Baz => (Baz | Qux)
+
+ +Note that the replacements are not quoted. The exception is when you want to replace with the empty string, e.g. + +

+A: Foo | Bar | Baz
+
+# Makes B the equivalent of Foo | Bar
+B extends A: | Baz => ""
+
+ +Currently there is no escaping supported - if you want to replace "," or "=>" characters you'll have to use full replacement + +#### Full replacement + +You can specify an entirely new rule in the same format as a non-inheriting rule, eg. + +

+A: Foo | Bar | Baz
+
+B extends A: Foo | Bar | (Baz Qux)
+
+ +This is useful is the rule changes too much for text replacement to be readable, but want to keep the storage logic + ### Pragmas When opening a parser comment block, if instead of a name (or no name) you put a word starting with '!', that comment block is treated as a pragma - not @@ -225,6 +326,4 @@ part of the parser language itself, but some other instruction to the compiler. - Allow inline-ing of rules into other rules for speed - More optimisation - Make Parser-parser be self-generated, instead of a bad hand rolled parser like it is now. -- Slighly more powerfull expressions: `${parent.q}`, `${foo()->bar}`, etc. -- Need to properly escape all literals. Expressions currently need to be in '', not "" - PHP token parser, and other token streams, instead of strings only like now diff --git a/thirdparty/php-peg/tests/ParserInheritanceTest.php b/thirdparty/php-peg/tests/ParserInheritanceTest.php new file mode 100644 index 000000000..c652fac83 --- /dev/null +++ b/thirdparty/php-peg/tests/ParserInheritanceTest.php @@ -0,0 +1,123 @@ +buildParser(' + /*!* BasicInheritanceTestParser + Foo: "a" + Bar extends Foo + */ + '); + + $this->assertTrue($parser->matches('Foo', 'a')); + $this->assertTrue($parser->matches('Bar', 'a')); + + $this->assertFalse($parser->matches('Foo', 'b')); + $this->assertFalse($parser->matches('Bar', 'b')); + } + + + public function testBasicInheritanceConstructFallback() { + + $parser = $this->buildParser(' + /*!* BasicInheritanceConstructFallbackParser + Foo: "a" + function __construct(&$res){ $res["test"] = "test"; } + Bar extends Foo + */ + '); + + $res = $parser->match('Foo', 'a'); + $this->assertEquals($res['test'], 'test'); + + $res = $parser->match('Bar', 'a'); + $this->assertEquals($res['test'], 'test'); + + $parser = $this->buildParser(' + /*!* BasicInheritanceConstructFallbackParser2 + Foo: "a" + function __construct(&$res){ $res["testa"] = "testa"; } + Bar extends Foo + function __construct(&$res){ $res["testb"] = "testb"; } + */ + '); + + $res = $parser->match('Foo', 'a'); + $this->assertArrayHasKey('testa', $res); + $this->assertEquals($res['testa'], 'testa'); + $this->assertArrayNotHasKey('testb', $res); + + $res = $parser->match('Bar', 'a'); + $this->assertArrayHasKey('testb', $res); + $this->assertEquals($res['testb'], 'testb'); + $this->assertArrayNotHasKey('testa', $res); + + } + + public function testBasicInheritanceStoreFallback() { + + $parser = $this->buildParser(' + /*!* BasicInheritanceStoreFallbackParser + Foo: Pow:"a" + function *(&$res, $sub){ $res["test"] = "test"; } + Bar extends Foo + */ + '); + + $res = $parser->match('Foo', 'a'); + $this->assertEquals($res['test'], 'test'); + + $res = $parser->match('Bar', 'a'); + $this->assertEquals($res['test'], 'test'); + + $parser = $this->buildParser(' + /*!* BasicInheritanceStoreFallbackParser2 + Foo: Pow:"a" Zap:"b" + function *(&$res, $sub){ $res["testa"] = "testa"; } + Bar extends Foo + function *(&$res, $sub){ $res["testb"] = "testb"; } + Baz extends Foo + function Zap(&$res, $sub){ $res["testc"] = "testc"; } + */ + '); + + $res = $parser->match('Foo', 'ab'); + $this->assertArrayHasKey('testa', $res); + $this->assertEquals($res['testa'], 'testa'); + $this->assertArrayNotHasKey('testb', $res); + + $res = $parser->match('Bar', 'ab'); + $this->assertArrayHasKey('testb', $res); + $this->assertEquals($res['testb'], 'testb'); + $this->assertArrayNotHasKey('testa', $res); + + $res = $parser->match('Baz', 'ab'); + $this->assertArrayHasKey('testa', $res); + $this->assertEquals($res['testa'], 'testa'); + $this->assertArrayHasKey('testc', $res); + $this->assertEquals($res['testc'], 'testc'); + $this->assertArrayNotHasKey('testb', $res); + } + + public function testInheritanceByReplacement() { + $parser = $this->buildParser(' + /*!* InheritanceByReplacementParser + A: "a" + B: "b" + Foo: A B + Bar extends Foo; B => A + Baz extends Foo; A => "" + */ + '); + + $parser->assertMatches('Foo', 'ab'); + $parser->assertMatches('Bar', 'aa'); + $parser->assertMatches('Baz', 'b'); + } + + +} \ No newline at end of file diff --git a/thirdparty/php-peg/tests/ParserSyntaxTest.php b/thirdparty/php-peg/tests/ParserSyntaxTest.php new file mode 100644 index 000000000..74defdddb --- /dev/null +++ b/thirdparty/php-peg/tests/ParserSyntaxTest.php @@ -0,0 +1,26 @@ +buildParser(' + /*!* BasicRuleSyntax + Foo: "a" "b" + Bar: "a" + "b" + Baz: + "a" "b" + Qux: + "a" + "b" + */ + '); + + $parser->assertMatches('Foo', 'ab'); + $parser->assertMatches('Bar', 'ab'); + $parser->assertMatches('Baz', 'ab'); + $parser->assertMatches('Qux', 'ab'); + } +} \ No newline at end of file diff --git a/thirdparty/php-peg/tests/ParserTestBase.php b/thirdparty/php-peg/tests/ParserTestBase.php new file mode 100644 index 000000000..90a148c5b --- /dev/null +++ b/thirdparty/php-peg/tests/ParserTestBase.php @@ -0,0 +1,48 @@ +testcase = $testcase; + $this->class = $class; + } + + function match($method, $string, $allowPartial = false){ + $class = $this->class; + $func = 'match_'.$method; + + $parser = new $class($string); + $res = $parser->$func(); + return ($allowPartial || $parser->pos == strlen($string)) ? $res : false; + } + + function matches($method, $string, $allowPartial = false){ + return $this->match($method, $string, $allowPartial) !== false; + } + + function assertMatches($method, $string, $message = null){ + $this->testcase->assertTrue($this->matches($method, $string), $message ? $message : "Assert parser method $method matches string $string"); + } + + function assertDoesntMatch($method, $string, $message = null){ + $this->testcase->assertFalse($this->matches($method, $string), $message ? $message : "Assert parser method $method doesn't match string $string"); + } +} + +class ParserTestBase extends PHPUnit_Framework_TestCase { + + function buildParser($parser) { + $class = 'Parser'.sha1($parser); + + echo ParserCompiler::compile("class $class extends Parser {\n $parser\n}") . "\n\n\n"; + eval(ParserCompiler::compile("class $class extends Parser {\n $parser\n}")); + return new ParserTestWrapper($this, $class); + } + +} \ No newline at end of file diff --git a/thirdparty/php-peg/tests/ParserVariablesTest.php b/thirdparty/php-peg/tests/ParserVariablesTest.php new file mode 100644 index 000000000..e941200a5 --- /dev/null +++ b/thirdparty/php-peg/tests/ParserVariablesTest.php @@ -0,0 +1,55 @@ +buildParser(' + /*!* BasicVariables + Foo: Letter:"a" "$Letter" + Bar: Letter:"b" "$Letter $Letter" + Baz: Letter:"c" "$Letter a $Letter a" + Qux: Letter:"d" "{$Letter}a{$Letter}a" + */ + '); + + $parser->assertMatches('Foo', 'aa'); + $parser->assertMatches('Bar', 'bb b'); + $parser->assertMatches('Baz', 'cc a c a'); + $parser->assertMatches('Qux', 'ddada'); + } + + public function testRecurseOnVariables() { + $parser = $this->buildParser(' + /*!* RecurseOnVariablesParser + A: "a" + B: "b" + Foo: $Template + Bar: Foo + function __construct(&$res){ $res["Template"] = "A"; } + Baz: Foo + function __construct(&$res){ $res["Template"] = "B"; } + */ + '); + + $parser->assertMatches('Bar', 'a'); $parser->assertDoesntMatch('Bar', 'b'); + $parser->assertMatches('Baz', 'b'); $parser->assertDoesntMatch('Baz', 'a'); + } + + public function testSetOnRuleVariables() { + $parser = $this->buildParser(' + /*!* SetOnRuleVariablesParser + A: "a" + B: "b" + Foo: $Template + Bar (Template = A): Foo + Baz (Template = B): Foo + */ + '); + + $parser->assertMatches('Bar', 'a'); + $parser->assertMatches('Baz', 'b'); + } + +} \ No newline at end of file From 29c06edd230650e27eea0e3fd4dae420c8e6f7d6 Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Mon, 28 Feb 2011 16:12:41 +1300 Subject: [PATCH 13/15] ENHANCEMENT: Add back in partial caching --- core/SSTemplateParser.php | 3973 +++++++++++++++++++----------- core/SSTemplateParser.php.inc | 222 +- tests/SSViewerCacheBlockTest.php | 5 + 3 files changed, 2669 insertions(+), 1531 deletions(-) diff --git a/core/SSTemplateParser.php b/core/SSTemplateParser.php index 55066f984..a34c953f8 100644 --- a/core/SSTemplateParser.php +++ b/core/SSTemplateParser.php @@ -67,89 +67,315 @@ class SSTemplateParser extends Parser { */ protected $includeDebuggingComments = false; + /** + * Override the function that constructs the result arrays to also prepare a 'php' item in the array + */ + function construct($matchrule, $name, $arguments = null) { + $res = parent::construct($matchrule, $name, $arguments); + if (!isset($res['php'])) $res['php'] = ''; + return $res; + } + + /* Template: (Comment | If | Require | CacheBlock | UncachedBlock | OldI18NTag | ClosedBlock | OpenBlock | MalformedBlock | Injection | Text)+ */ + protected $match_Template_typestack = array('Template'); + function match_Template ($stack = array()) { + $matchrule = "Template"; $result = $this->construct($matchrule, $matchrule, null); + $count = 0; + while (true) { + $res_42 = $result; + $pos_42 = $this->pos; + $_41 = NULL; + do { + $_39 = NULL; + do { + $res_0 = $result; + $pos_0 = $this->pos; + $matcher = 'match_'.'Comment'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_39 = TRUE; break; + } + $result = $res_0; + $this->pos = $pos_0; + $_37 = NULL; + do { + $res_2 = $result; + $pos_2 = $this->pos; + $matcher = 'match_'.'If'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_37 = TRUE; break; + } + $result = $res_2; + $this->pos = $pos_2; + $_35 = NULL; + do { + $res_4 = $result; + $pos_4 = $this->pos; + $matcher = 'match_'.'Require'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_35 = TRUE; break; + } + $result = $res_4; + $this->pos = $pos_4; + $_33 = NULL; + do { + $res_6 = $result; + $pos_6 = $this->pos; + $matcher = 'match_'.'CacheBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_33 = TRUE; break; + } + $result = $res_6; + $this->pos = $pos_6; + $_31 = NULL; + do { + $res_8 = $result; + $pos_8 = $this->pos; + $matcher = 'match_'.'UncachedBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_31 = TRUE; break; + } + $result = $res_8; + $this->pos = $pos_8; + $_29 = NULL; + do { + $res_10 = $result; + $pos_10 = $this->pos; + $matcher = 'match_'.'OldI18NTag'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_29 = TRUE; break; + } + $result = $res_10; + $this->pos = $pos_10; + $_27 = NULL; + do { + $res_12 = $result; + $pos_12 = $this->pos; + $matcher = 'match_'.'ClosedBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_27 = TRUE; break; + } + $result = $res_12; + $this->pos = $pos_12; + $_25 = NULL; + do { + $res_14 = $result; + $pos_14 = $this->pos; + $matcher = 'match_'.'OpenBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_25 = TRUE; break; + } + $result = $res_14; + $this->pos = $pos_14; + $_23 = NULL; + do { + $res_16 = $result; + $pos_16 = $this->pos; + $matcher = 'match_'.'MalformedBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_23 = TRUE; break; + } + $result = $res_16; + $this->pos = $pos_16; + $_21 = NULL; + do { + $res_18 = $result; + $pos_18 = $this->pos; + $matcher = 'match_'.'Injection'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_21 = TRUE; break; + } + $result = $res_18; + $this->pos = $pos_18; + $matcher = 'match_'.'Text'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_21 = TRUE; break; + } + $result = $res_18; + $this->pos = $pos_18; + $_21 = FALSE; break; + } + while(0); + if( $_21 === TRUE ) { $_23 = TRUE; break; } + $result = $res_16; + $this->pos = $pos_16; + $_23 = FALSE; break; + } + while(0); + if( $_23 === TRUE ) { $_25 = TRUE; break; } + $result = $res_14; + $this->pos = $pos_14; + $_25 = FALSE; break; + } + while(0); + if( $_25 === TRUE ) { $_27 = TRUE; break; } + $result = $res_12; + $this->pos = $pos_12; + $_27 = FALSE; break; + } + while(0); + if( $_27 === TRUE ) { $_29 = TRUE; break; } + $result = $res_10; + $this->pos = $pos_10; + $_29 = FALSE; break; + } + while(0); + if( $_29 === TRUE ) { $_31 = TRUE; break; } + $result = $res_8; + $this->pos = $pos_8; + $_31 = FALSE; break; + } + while(0); + if( $_31 === TRUE ) { $_33 = TRUE; break; } + $result = $res_6; + $this->pos = $pos_6; + $_33 = FALSE; break; + } + while(0); + if( $_33 === TRUE ) { $_35 = TRUE; break; } + $result = $res_4; + $this->pos = $pos_4; + $_35 = FALSE; break; + } + while(0); + if( $_35 === TRUE ) { $_37 = TRUE; break; } + $result = $res_2; + $this->pos = $pos_2; + $_37 = FALSE; break; + } + while(0); + if( $_37 === TRUE ) { $_39 = TRUE; break; } + $result = $res_0; + $this->pos = $pos_0; + $_39 = FALSE; break; + } + while(0); + if( $_39 === FALSE) { $_41 = FALSE; break; } + $_41 = TRUE; break; + } + while(0); + if( $_41 === FALSE) { + $result = $res_42; + $this->pos = $pos_42; + unset( $res_42 ); + unset( $pos_42 ); + break; + } + $count += 1; + } + if ($count > 0) { return $this->finalise($result); } + else { return FALSE; } + } + + + + function Template_STR(&$res, $sub) { + $res['php'] .= $sub['php'] . PHP_EOL ; + } + /* Word: / [A-Za-z_] [A-Za-z0-9_]* / */ - function match_Word ($substack = array()) { - $result = array("name"=>"Word", "text"=>""); - $_0 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_0->expand('/ [A-Za-z_] [A-Za-z0-9_]* /') ) ) !== FALSE) { + protected $match_Word_typestack = array('Word'); + function match_Word ($stack = array()) { + $matchrule = "Word"; $result = $this->construct($matchrule, $matchrule, null); + if (( $subres = $this->rx( '/ [A-Za-z_] [A-Za-z0-9_]* /' ) ) !== FALSE) { $result["text"] .= $subres; - return $result; + return $this->finalise($result); } else { return FALSE; } } /* Number: / [0-9]+ / */ - function match_Number ($substack = array()) { - $result = array("name"=>"Number", "text"=>""); - $_2 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_2->expand('/ [0-9]+ /') ) ) !== FALSE) { + protected $match_Number_typestack = array('Number'); + function match_Number ($stack = array()) { + $matchrule = "Number"; $result = $this->construct($matchrule, $matchrule, null); + if (( $subres = $this->rx( '/ [0-9]+ /' ) ) !== FALSE) { $result["text"] .= $subres; - return $result; + return $this->finalise($result); } else { return FALSE; } } /* Value: / [A-Za-z0-9_]+ / */ - function match_Value ($substack = array()) { - $result = array("name"=>"Value", "text"=>""); - $_4 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_4->expand('/ [A-Za-z0-9_]+ /') ) ) !== FALSE) { + protected $match_Value_typestack = array('Value'); + function match_Value ($stack = array()) { + $matchrule = "Value"; $result = $this->construct($matchrule, $matchrule, null); + if (( $subres = $this->rx( '/ [A-Za-z0-9_]+ /' ) ) !== FALSE) { $result["text"] .= $subres; - return $result; + return $this->finalise($result); } else { return FALSE; } } /* CallArguments: :Argument ( < "," < :Argument )* */ - function match_CallArguments ($substack = array()) { - $result = $this->construct( "CallArguments" ); - $_13 = NULL; + protected $match_CallArguments_typestack = array('CallArguments'); + function match_CallArguments ($stack = array()) { + $matchrule = "CallArguments"; $result = $this->construct($matchrule, $matchrule, null); + $_53 = NULL; do { - $key = "Argument"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Argument'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Argument" ); } - else { $_13 = FALSE; break; } + else { $_53 = FALSE; break; } while (true) { - $res_12 = $result; - $pos_12 = $this->pos; - $_11 = NULL; + $res_52 = $result; + $pos_52 = $this->pos; + $_51 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - if (substr($this->string,$this->pos,1) == ",") { + if (substr($this->string,$this->pos,1) == ',') { $this->pos += 1; - $result["text"] .= ","; + $result["text"] .= ','; } - else { $_11 = FALSE; break; } + else { $_51 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "Argument"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Argument'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Argument" ); } - else { $_11 = FALSE; break; } - $_11 = TRUE; break; + else { $_51 = FALSE; break; } + $_51 = TRUE; break; } while(0); - if( $_11 === FALSE) { - $result = $res_12; - $this->pos = $pos_12; - unset( $res_12 ); - unset( $pos_12 ); + if( $_51 === FALSE) { + $result = $res_52; + $this->pos = $pos_52; + unset( $res_52 ); + unset( $pos_52 ); break; } } - $_13 = TRUE; break; + $_53 = TRUE; break; } while(0); - if( $_13 === TRUE ) { - return $this->finalise( "CallArguments", $result ); - } - if( $_13 === FALSE) { return FALSE; } + if( $_53 === TRUE ) { return $this->finalise($result); } + if( $_53 === FALSE) { return FALSE; } } @@ -160,188 +386,185 @@ class SSTemplateParser extends Parser { * to numbers when needed. */ function CallArguments_Argument(&$res, $sub) { - if (isset($res['php'])) $res['php'] .= ', '; - else $res['php'] = ''; + if (!empty($res['php'])) $res['php'] .= ', '; $res['php'] .= ($sub['ArgumentMode'] == 'default') ? $sub['string_php'] : str_replace('$$FINAL', 'XML_val', $sub['php']); } /* Call: Method:Word ( "(" < :CallArguments? > ")" )? */ - function match_Call ($substack = array()) { - $result = $this->construct( "Call" ); - $_23 = NULL; + protected $match_Call_typestack = array('Call'); + function match_Call ($stack = array()) { + $matchrule = "Call"; $result = $this->construct($matchrule, $matchrule, null); + $_63 = NULL; do { - $key = "Word"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Word'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Method" ); } - else { $_23 = FALSE; break; } - $res_22 = $result; - $pos_22 = $this->pos; - $_21 = NULL; + else { $_63 = FALSE; break; } + $res_62 = $result; + $pos_62 = $this->pos; + $_61 = NULL; do { - if (substr($this->string,$this->pos,1) == "(") { + if (substr($this->string,$this->pos,1) == '(') { $this->pos += 1; - $result["text"] .= "("; + $result["text"] .= '('; } - else { $_21 = FALSE; break; } + else { $_61 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_18 = $result; - $pos_18 = $this->pos; - $key = "CallArguments"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_CallArguments(array_merge($substack, array($result))) ) ); + $res_58 = $result; + $pos_58 = $this->pos; + $matcher = 'match_'.'CallArguments'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "CallArguments" ); } else { - $result = $res_18; - $this->pos = $pos_18; - unset( $res_18 ); - unset( $pos_18 ); + $result = $res_58; + $this->pos = $pos_58; + unset( $res_58 ); + unset( $pos_58 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - if (substr($this->string,$this->pos,1) == ")") { + if (substr($this->string,$this->pos,1) == ')') { $this->pos += 1; - $result["text"] .= ")"; + $result["text"] .= ')'; } - else { $_21 = FALSE; break; } - $_21 = TRUE; break; + else { $_61 = FALSE; break; } + $_61 = TRUE; break; } while(0); - if( $_21 === FALSE) { - $result = $res_22; - $this->pos = $pos_22; - unset( $res_22 ); - unset( $pos_22 ); + if( $_61 === FALSE) { + $result = $res_62; + $this->pos = $pos_62; + unset( $res_62 ); + unset( $pos_62 ); } - $_23 = TRUE; break; + $_63 = TRUE; break; } while(0); - if( $_23 === TRUE ) { - return $this->finalise( "Call", $result ); - } - if( $_23 === FALSE) { return FALSE; } + if( $_63 === TRUE ) { return $this->finalise($result); } + if( $_63 === FALSE) { return FALSE; } } /* LookupStep: :Call &"." */ - function match_LookupStep ($substack = array()) { - $result = $this->construct( "LookupStep" ); - $_27 = NULL; + protected $match_LookupStep_typestack = array('LookupStep'); + function match_LookupStep ($stack = array()) { + $matchrule = "LookupStep"; $result = $this->construct($matchrule, $matchrule, null); + $_67 = NULL; do { - $key = "Call"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Call(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Call'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Call" ); } - else { $_27 = FALSE; break; } - $res_26 = $result; - $pos_26 = $this->pos; - if (substr($this->string,$this->pos,1) == ".") { + else { $_67 = FALSE; break; } + $res_66 = $result; + $pos_66 = $this->pos; + if (substr($this->string,$this->pos,1) == '.') { $this->pos += 1; - $result["text"] .= "."; - $result = $res_26; - $this->pos = $pos_26; + $result["text"] .= '.'; + $result = $res_66; + $this->pos = $pos_66; } else { - $result = $res_26; - $this->pos = $pos_26; - $_27 = FALSE; break; + $result = $res_66; + $this->pos = $pos_66; + $_67 = FALSE; break; } - $_27 = TRUE; break; + $_67 = TRUE; break; } while(0); - if( $_27 === TRUE ) { - return $this->finalise( "LookupStep", $result ); - } - if( $_27 === FALSE) { return FALSE; } + if( $_67 === TRUE ) { return $this->finalise($result); } + if( $_67 === FALSE) { return FALSE; } } /* LastLookupStep: :Call */ - function match_LastLookupStep ($substack = array()) { - $result = $this->construct( "LastLookupStep" ); - $key = "Call"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Call(array_merge($substack, array($result))) ) ); + protected $match_LastLookupStep_typestack = array('LastLookupStep'); + function match_LastLookupStep ($stack = array()) { + $matchrule = "LastLookupStep"; $result = $this->construct($matchrule, $matchrule, null); + $matcher = 'match_'.'Call'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Call" ); - return $this->finalise( "LastLookupStep", $result ); + return $this->finalise($result); } else { return FALSE; } } /* Lookup: LookupStep ("." LookupStep)* "." LastLookupStep | LastLookupStep */ - function match_Lookup ($substack = array()) { - $result = $this->construct( "Lookup" ); - $_41 = NULL; + protected $match_Lookup_typestack = array('Lookup'); + function match_Lookup ($stack = array()) { + $matchrule = "Lookup"; $result = $this->construct($matchrule, $matchrule, null); + $_81 = NULL; do { - $res_30 = $result; - $pos_30 = $this->pos; - $_38 = NULL; + $res_70 = $result; + $pos_70 = $this->pos; + $_78 = NULL; do { - $key = "LookupStep"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_LookupStep(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'LookupStep'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_38 = FALSE; break; } + else { $_78 = FALSE; break; } while (true) { - $res_35 = $result; - $pos_35 = $this->pos; - $_34 = NULL; + $res_75 = $result; + $pos_75 = $this->pos; + $_74 = NULL; do { - if (substr($this->string,$this->pos,1) == ".") { + if (substr($this->string,$this->pos,1) == '.') { $this->pos += 1; - $result["text"] .= "."; + $result["text"] .= '.'; } - else { $_34 = FALSE; break; } - $key = "LookupStep"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_LookupStep(array_merge($substack, array($result))) ) ); + else { $_74 = FALSE; break; } + $matcher = 'match_'.'LookupStep'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_34 = FALSE; break; } - $_34 = TRUE; break; + else { $_74 = FALSE; break; } + $_74 = TRUE; break; } while(0); - if( $_34 === FALSE) { - $result = $res_35; - $this->pos = $pos_35; - unset( $res_35 ); - unset( $pos_35 ); + if( $_74 === FALSE) { + $result = $res_75; + $this->pos = $pos_75; + unset( $res_75 ); + unset( $pos_75 ); break; } } - if (substr($this->string,$this->pos,1) == ".") { + if (substr($this->string,$this->pos,1) == '.') { $this->pos += 1; - $result["text"] .= "."; + $result["text"] .= '.'; } - else { $_38 = FALSE; break; } - $key = "LastLookupStep"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_LastLookupStep(array_merge($substack, array($result))) ) ); + else { $_78 = FALSE; break; } + $matcher = 'match_'.'LastLookupStep'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_38 = FALSE; break; } - $_38 = TRUE; break; + else { $_78 = FALSE; break; } + $_78 = TRUE; break; } while(0); - if( $_38 === TRUE ) { $_41 = TRUE; break; } - $result = $res_30; - $this->pos = $pos_30; - $key = "LastLookupStep"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_LastLookupStep(array_merge($substack, array($result))) ) ); + if( $_78 === TRUE ) { $_81 = TRUE; break; } + $result = $res_70; + $this->pos = $pos_70; + $matcher = 'match_'.'LastLookupStep'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_41 = TRUE; break; + $_81 = TRUE; break; } - $result = $res_30; - $this->pos = $pos_30; - $_41 = FALSE; break; + $result = $res_70; + $this->pos = $pos_70; + $_81 = FALSE; break; } while(0); - if( $_41 === TRUE ) { - return $this->finalise( "Lookup", $result ); - } - if( $_41 === FALSE) { return FALSE; } + if( $_81 === TRUE ) { return $this->finalise($result); } + if( $_81 === FALSE) { return FALSE; } } @@ -379,90 +602,86 @@ class SSTemplateParser extends Parser { } /* SimpleInjection: '$' :Lookup */ - function match_SimpleInjection ($substack = array()) { - $result = $this->construct( "SimpleInjection" ); - $_45 = NULL; + protected $match_SimpleInjection_typestack = array('SimpleInjection'); + function match_SimpleInjection ($stack = array()) { + $matchrule = "SimpleInjection"; $result = $this->construct($matchrule, $matchrule, null); + $_85 = NULL; do { if (substr($this->string,$this->pos,1) == '$') { $this->pos += 1; $result["text"] .= '$'; } - else { $_45 = FALSE; break; } - $key = "Lookup"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Lookup(array_merge($substack, array($result))) ) ); + else { $_85 = FALSE; break; } + $matcher = 'match_'.'Lookup'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Lookup" ); } - else { $_45 = FALSE; break; } - $_45 = TRUE; break; + else { $_85 = FALSE; break; } + $_85 = TRUE; break; } while(0); - if( $_45 === TRUE ) { - return $this->finalise( "SimpleInjection", $result ); - } - if( $_45 === FALSE) { return FALSE; } + if( $_85 === TRUE ) { return $this->finalise($result); } + if( $_85 === FALSE) { return FALSE; } } /* BracketInjection: '{$' :Lookup "}" */ - function match_BracketInjection ($substack = array()) { - $result = $this->construct( "BracketInjection" ); - $_51 = NULL; + protected $match_BracketInjection_typestack = array('BracketInjection'); + function match_BracketInjection ($stack = array()) { + $matchrule = "BracketInjection"; $result = $this->construct($matchrule, $matchrule, null); + $_90 = NULL; do { - $_47 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_47->expand('{$') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_51 = FALSE; break; } - $key = "Lookup"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Lookup(array_merge($substack, array($result))) ) ); + if (( $subres = $this->literal( '{$' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_90 = FALSE; break; } + $matcher = 'match_'.'Lookup'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Lookup" ); } - else { $_51 = FALSE; break; } - if (substr($this->string,$this->pos,1) == "}") { + else { $_90 = FALSE; break; } + if (substr($this->string,$this->pos,1) == '}') { $this->pos += 1; - $result["text"] .= "}"; + $result["text"] .= '}'; } - else { $_51 = FALSE; break; } - $_51 = TRUE; break; + else { $_90 = FALSE; break; } + $_90 = TRUE; break; } while(0); - if( $_51 === TRUE ) { - return $this->finalise( "BracketInjection", $result ); - } - if( $_51 === FALSE) { return FALSE; } + if( $_90 === TRUE ) { return $this->finalise($result); } + if( $_90 === FALSE) { return FALSE; } } /* Injection: BracketInjection | SimpleInjection */ - function match_Injection ($substack = array()) { - $result = $this->construct( "Injection" ); - $_56 = NULL; + protected $match_Injection_typestack = array('Injection'); + function match_Injection ($stack = array()) { + $matchrule = "Injection"; $result = $this->construct($matchrule, $matchrule, null); + $_95 = NULL; do { - $res_53 = $result; - $pos_53 = $this->pos; - $key = "BracketInjection"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BracketInjection(array_merge($substack, array($result))) ) ); + $res_92 = $result; + $pos_92 = $this->pos; + $matcher = 'match_'.'BracketInjection'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_56 = TRUE; break; + $_95 = TRUE; break; } - $result = $res_53; - $this->pos = $pos_53; - $key = "SimpleInjection"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_SimpleInjection(array_merge($substack, array($result))) ) ); + $result = $res_92; + $this->pos = $pos_92; + $matcher = 'match_'.'SimpleInjection'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_56 = TRUE; break; + $_95 = TRUE; break; } - $result = $res_53; - $this->pos = $pos_53; - $_56 = FALSE; break; + $result = $res_92; + $this->pos = $pos_92; + $_95 = FALSE; break; } while(0); - if( $_56 === TRUE ) { - return $this->finalise( "Injection", $result ); - } - if( $_56 === FALSE) { return FALSE; } + if( $_95 === TRUE ) { return $this->finalise($result); } + if( $_95 === FALSE) { return FALSE; } } @@ -472,13 +691,14 @@ class SSTemplateParser extends Parser { } /* DollarMarkedLookup: SimpleInjection */ - function match_DollarMarkedLookup ($substack = array()) { - $result = $this->construct( "DollarMarkedLookup" ); - $key = "SimpleInjection"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_SimpleInjection(array_merge($substack, array($result))) ) ); + protected $match_DollarMarkedLookup_typestack = array('DollarMarkedLookup'); + function match_DollarMarkedLookup ($stack = array()) { + $matchrule = "DollarMarkedLookup"; $result = $this->construct($matchrule, $matchrule, null); + $matcher = 'match_'.'SimpleInjection'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - return $this->finalise( "DollarMarkedLookup", $result ); + return $this->finalise($result); } else { return FALSE; } } @@ -490,160 +710,151 @@ class SSTemplateParser extends Parser { } /* QuotedString: q:/['"]/ String:/ (\\\\ | \\. | [^$q\\])* / '$q' */ - function match_QuotedString ($substack = array()) { - $result = $this->construct( "QuotedString" ); - $_67 = NULL; + protected $match_QuotedString_typestack = array('QuotedString'); + function match_QuotedString ($stack = array()) { + $matchrule = "QuotedString"; $result = $this->construct($matchrule, $matchrule, null); + $_101 = NULL; do { - $substack[] = $result; - $result = $this->construct( "q" ); - $_59 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_59->expand('/[\'"]/') ) ) !== FALSE) { + $stack[] = $result; $result = $this->construct( $matchrule, "q" ); + if (( $subres = $this->rx( '/[\'"]/' ) ) !== FALSE) { $result["text"] .= $subres; - $subres = $result ; - $result = array_pop( $substack ) ; + $subres = $result; $result = array_pop($stack); $this->store( $result, $subres, 'q' ); } else { - $result = array_pop( $substack ) ; - $_67 = FALSE; break; + $result = array_pop($stack); + $_101 = FALSE; break; } - $substack[] = $result; - $result = $this->construct( "String" ); - $_62 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_62->expand('/ (\\\\\\\\ | \\\\. | [^$q\\\\])* /') ) ) !== FALSE) { + $stack[] = $result; $result = $this->construct( $matchrule, "String" ); + if (( $subres = $this->rx( '/ (\\\\\\\\ | \\\\. | [^'.$this->expression($result, $stack, 'q').'\\\\])* /' ) ) !== FALSE) { $result["text"] .= $subres; - $subres = $result ; - $result = array_pop( $substack ) ; + $subres = $result; $result = array_pop($stack); $this->store( $result, $subres, 'String' ); } else { - $result = array_pop( $substack ) ; - $_67 = FALSE; break; + $result = array_pop($stack); + $_101 = FALSE; break; } - $_65 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_65->expand('$q') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_67 = FALSE; break; } - $_67 = TRUE; break; + if (( $subres = $this->literal( ''.$this->expression($result, $stack, 'q').'' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_101 = FALSE; break; } + $_101 = TRUE; break; } while(0); - if( $_67 === TRUE ) { - return $this->finalise( "QuotedString", $result ); - } - if( $_67 === FALSE) { return FALSE; } + if( $_101 === TRUE ) { return $this->finalise($result); } + if( $_101 === FALSE) { return FALSE; } } /* FreeString: /[^,)%!=|&]+/ */ - function match_FreeString ($substack = array()) { - $result = array("name"=>"FreeString", "text"=>""); - $_69 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_69->expand('/[^,)%!=|&]+/') ) ) !== FALSE) { + protected $match_FreeString_typestack = array('FreeString'); + function match_FreeString ($stack = array()) { + $matchrule = "FreeString"; $result = $this->construct($matchrule, $matchrule, null); + if (( $subres = $this->rx( '/[^,)%!=|&]+/' ) ) !== FALSE) { $result["text"] .= $subres; - return $result; + return $this->finalise($result); } else { return FALSE; } } /* Argument: -:DollarMarkedLookup | -:QuotedString | -:Lookup !(< FreeString)| -:FreeString */ - function match_Argument ($substack = array()) { - $result = $this->construct( "Argument" ); - $_88 = NULL; + :DollarMarkedLookup | + :QuotedString | + :Lookup !(< FreeString)| + :FreeString */ + protected $match_Argument_typestack = array('Argument'); + function match_Argument ($stack = array()) { + $matchrule = "Argument"; $result = $this->construct($matchrule, $matchrule, null); + $_121 = NULL; do { - $res_71 = $result; - $pos_71 = $this->pos; - $key = "DollarMarkedLookup"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_DollarMarkedLookup(array_merge($substack, array($result))) ) ); + $res_104 = $result; + $pos_104 = $this->pos; + $matcher = 'match_'.'DollarMarkedLookup'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "DollarMarkedLookup" ); - $_88 = TRUE; break; + $_121 = TRUE; break; } - $result = $res_71; - $this->pos = $pos_71; - $_86 = NULL; + $result = $res_104; + $this->pos = $pos_104; + $_119 = NULL; do { - $res_73 = $result; - $pos_73 = $this->pos; - $key = "QuotedString"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_QuotedString(array_merge($substack, array($result))) ) ); + $res_106 = $result; + $pos_106 = $this->pos; + $matcher = 'match_'.'QuotedString'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "QuotedString" ); - $_86 = TRUE; break; + $_119 = TRUE; break; } - $result = $res_73; - $this->pos = $pos_73; - $_84 = NULL; + $result = $res_106; + $this->pos = $pos_106; + $_117 = NULL; do { - $res_75 = $result; - $pos_75 = $this->pos; - $_81 = NULL; + $res_108 = $result; + $pos_108 = $this->pos; + $_114 = NULL; do { - $key = "Lookup"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Lookup(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Lookup'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Lookup" ); } - else { $_81 = FALSE; break; } - $res_80 = $result; - $pos_80 = $this->pos; - $_79 = NULL; + else { $_114 = FALSE; break; } + $res_113 = $result; + $pos_113 = $this->pos; + $_112 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "FreeString"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_FreeString(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'FreeString'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_79 = FALSE; break; } - $_79 = TRUE; break; + else { $_112 = FALSE; break; } + $_112 = TRUE; break; } while(0); - if( $_79 === TRUE ) { - $result = $res_80; - $this->pos = $pos_80; - $_81 = FALSE; break; + if( $_112 === TRUE ) { + $result = $res_113; + $this->pos = $pos_113; + $_114 = FALSE; break; } - if( $_79 === FALSE) { - $result = $res_80; - $this->pos = $pos_80; + if( $_112 === FALSE) { + $result = $res_113; + $this->pos = $pos_113; } - $_81 = TRUE; break; + $_114 = TRUE; break; } while(0); - if( $_81 === TRUE ) { $_84 = TRUE; break; } - $result = $res_75; - $this->pos = $pos_75; - $key = "FreeString"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_FreeString(array_merge($substack, array($result))) ) ); + if( $_114 === TRUE ) { $_117 = TRUE; break; } + $result = $res_108; + $this->pos = $pos_108; + $matcher = 'match_'.'FreeString'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "FreeString" ); - $_84 = TRUE; break; + $_117 = TRUE; break; } - $result = $res_75; - $this->pos = $pos_75; - $_84 = FALSE; break; + $result = $res_108; + $this->pos = $pos_108; + $_117 = FALSE; break; } while(0); - if( $_84 === TRUE ) { $_86 = TRUE; break; } - $result = $res_73; - $this->pos = $pos_73; - $_86 = FALSE; break; + if( $_117 === TRUE ) { $_119 = TRUE; break; } + $result = $res_106; + $this->pos = $pos_106; + $_119 = FALSE; break; } while(0); - if( $_86 === TRUE ) { $_88 = TRUE; break; } - $result = $res_71; - $this->pos = $pos_71; - $_88 = FALSE; break; + if( $_119 === TRUE ) { $_121 = TRUE; break; } + $result = $res_104; + $this->pos = $pos_104; + $_121 = FALSE; break; } while(0); - if( $_88 === TRUE ) { - return $this->finalise( "Argument", $result ); - } - if( $_88 === FALSE) { return FALSE; } + if( $_121 === TRUE ) { return $this->finalise($result); } + if( $_121 === FALSE) { return FALSE; } } @@ -691,90 +902,85 @@ class SSTemplateParser extends Parser { } /* ComparisonOperator: "==" | "!=" | "=" */ - function match_ComparisonOperator ($substack = array()) { - $result = $this->construct( "ComparisonOperator" ); - $_99 = NULL; + protected $match_ComparisonOperator_typestack = array('ComparisonOperator'); + function match_ComparisonOperator ($stack = array()) { + $matchrule = "ComparisonOperator"; $result = $this->construct($matchrule, $matchrule, null); + $_130 = NULL; do { - $res_90 = $result; - $pos_90 = $this->pos; - $_91 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_91->expand("==") ) ) !== FALSE) { + $res_123 = $result; + $pos_123 = $this->pos; + if (( $subres = $this->literal( '==' ) ) !== FALSE) { $result["text"] .= $subres; - $_99 = TRUE; break; + $_130 = TRUE; break; } - $result = $res_90; - $this->pos = $pos_90; - $_97 = NULL; + $result = $res_123; + $this->pos = $pos_123; + $_128 = NULL; do { - $res_93 = $result; - $pos_93 = $this->pos; - $_94 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_94->expand("!=") ) ) !== FALSE) { + $res_125 = $result; + $pos_125 = $this->pos; + if (( $subres = $this->literal( '!=' ) ) !== FALSE) { $result["text"] .= $subres; - $_97 = TRUE; break; + $_128 = TRUE; break; } - $result = $res_93; - $this->pos = $pos_93; - if (substr($this->string,$this->pos,1) == "=") { + $result = $res_125; + $this->pos = $pos_125; + if (substr($this->string,$this->pos,1) == '=') { $this->pos += 1; - $result["text"] .= "="; - $_97 = TRUE; break; + $result["text"] .= '='; + $_128 = TRUE; break; } - $result = $res_93; - $this->pos = $pos_93; - $_97 = FALSE; break; + $result = $res_125; + $this->pos = $pos_125; + $_128 = FALSE; break; } while(0); - if( $_97 === TRUE ) { $_99 = TRUE; break; } - $result = $res_90; - $this->pos = $pos_90; - $_99 = FALSE; break; + if( $_128 === TRUE ) { $_130 = TRUE; break; } + $result = $res_123; + $this->pos = $pos_123; + $_130 = FALSE; break; } while(0); - if( $_99 === TRUE ) { - return $this->finalise( "ComparisonOperator", $result ); - } - if( $_99 === FALSE) { return FALSE; } + if( $_130 === TRUE ) { return $this->finalise($result); } + if( $_130 === FALSE) { return FALSE; } } /* Comparison: Argument < ComparisonOperator > Argument */ - function match_Comparison ($substack = array()) { - $result = $this->construct( "Comparison" ); - $_106 = NULL; + protected $match_Comparison_typestack = array('Comparison'); + function match_Comparison ($stack = array()) { + $matchrule = "Comparison"; $result = $this->construct($matchrule, $matchrule, null); + $_137 = NULL; do { - $key = "Argument"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Argument'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_106 = FALSE; break; } + else { $_137 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "ComparisonOperator"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ComparisonOperator(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'ComparisonOperator'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_106 = FALSE; break; } + else { $_137 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "Argument"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Argument'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_106 = FALSE; break; } - $_106 = TRUE; break; + else { $_137 = FALSE; break; } + $_137 = TRUE; break; } while(0); - if( $_106 === TRUE ) { - return $this->finalise( "Comparison", $result ); - } - if( $_106 === FALSE) { return FALSE; } + if( $_137 === TRUE ) { return $this->finalise($result); } + if( $_137 === FALSE) { return FALSE; } } function Comparison_Argument(&$res, $sub) { if ($sub['ArgumentMode'] == 'default') { - if (isset($res['php'])) $res['php'] .= $sub['string_php']; + if (!empty($res['php'])) $res['php'] .= $sub['string_php']; else $res['php'] = str_replace('$$FINAL', 'XML_val', $sub['lookup_php']); } else { - if (!isset($res['php'])) $res['php'] = ''; $res['php'] .= str_replace('$$FINAL', 'XML_val', $sub['php']); } } @@ -784,56 +990,48 @@ class SSTemplateParser extends Parser { } /* PresenceCheck: (Not:'not' <)? Argument */ - function match_PresenceCheck ($substack = array()) { - $result = $this->construct( "PresenceCheck" ); - $_115 = NULL; + protected $match_PresenceCheck_typestack = array('PresenceCheck'); + function match_PresenceCheck ($stack = array()) { + $matchrule = "PresenceCheck"; $result = $this->construct($matchrule, $matchrule, null); + $_144 = NULL; do { - $res_113 = $result; - $pos_113 = $this->pos; - $_112 = NULL; + $res_142 = $result; + $pos_142 = $this->pos; + $_141 = NULL; do { - $substack[] = $result; - $result = $this->construct( "Not" ); - $_108 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_108->expand('not') ) ) !== FALSE) { + $stack[] = $result; $result = $this->construct( $matchrule, "Not" ); + if (( $subres = $this->literal( 'not' ) ) !== FALSE) { $result["text"] .= $subres; - $subres = $result ; - $result = array_pop( $substack ) ; + $subres = $result; $result = array_pop($stack); $this->store( $result, $subres, 'Not' ); } else { - $result = array_pop( $substack ) ; - $_112 = FALSE; break; + $result = array_pop($stack); + $_141 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_112 = TRUE; break; + $_141 = TRUE; break; } while(0); - if( $_112 === FALSE) { - $result = $res_113; - $this->pos = $pos_113; - unset( $res_113 ); - unset( $pos_113 ); + if( $_141 === FALSE) { + $result = $res_142; + $this->pos = $pos_142; + unset( $res_142 ); + unset( $pos_142 ); } - $key = "Argument"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Argument'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_115 = FALSE; break; } - $_115 = TRUE; break; + else { $_144 = FALSE; break; } + $_144 = TRUE; break; } while(0); - if( $_115 === TRUE ) { - return $this->finalise( "PresenceCheck", $result ); - } - if( $_115 === FALSE) { return FALSE; } + if( $_144 === TRUE ) { return $this->finalise($result); } + if( $_144 === FALSE) { return FALSE; } } - function PresenceCheck__construct(&$res) { - $res['php'] = ''; - } - function PresenceCheck_Not(&$res, $sub) { $res['php'] = '!'; } @@ -851,35 +1049,34 @@ class SSTemplateParser extends Parser { } /* IfArgumentPortion: Comparison | PresenceCheck */ - function match_IfArgumentPortion ($substack = array()) { - $result = $this->construct( "IfArgumentPortion" ); - $_120 = NULL; + protected $match_IfArgumentPortion_typestack = array('IfArgumentPortion'); + function match_IfArgumentPortion ($stack = array()) { + $matchrule = "IfArgumentPortion"; $result = $this->construct($matchrule, $matchrule, null); + $_149 = NULL; do { - $res_117 = $result; - $pos_117 = $this->pos; - $key = "Comparison"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comparison(array_merge($substack, array($result))) ) ); + $res_146 = $result; + $pos_146 = $this->pos; + $matcher = 'match_'.'Comparison'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_120 = TRUE; break; + $_149 = TRUE; break; } - $result = $res_117; - $this->pos = $pos_117; - $key = "PresenceCheck"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_PresenceCheck(array_merge($substack, array($result))) ) ); + $result = $res_146; + $this->pos = $pos_146; + $matcher = 'match_'.'PresenceCheck'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_120 = TRUE; break; + $_149 = TRUE; break; } - $result = $res_117; - $this->pos = $pos_117; - $_120 = FALSE; break; + $result = $res_146; + $this->pos = $pos_146; + $_149 = FALSE; break; } while(0); - if( $_120 === TRUE ) { - return $this->finalise( "IfArgumentPortion", $result ); - } - if( $_120 === FALSE) { return FALSE; } + if( $_149 === TRUE ) { return $this->finalise($result); } + if( $_149 === FALSE) { return FALSE; } } @@ -889,91 +1086,84 @@ class SSTemplateParser extends Parser { } /* BooleanOperator: "||" | "&&" */ - function match_BooleanOperator ($substack = array()) { - $result = $this->construct( "BooleanOperator" ); - $_127 = NULL; + protected $match_BooleanOperator_typestack = array('BooleanOperator'); + function match_BooleanOperator ($stack = array()) { + $matchrule = "BooleanOperator"; $result = $this->construct($matchrule, $matchrule, null); + $_154 = NULL; do { - $res_122 = $result; - $pos_122 = $this->pos; - $_123 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_123->expand("||") ) ) !== FALSE) { + $res_151 = $result; + $pos_151 = $this->pos; + if (( $subres = $this->literal( '||' ) ) !== FALSE) { $result["text"] .= $subres; - $_127 = TRUE; break; + $_154 = TRUE; break; } - $result = $res_122; - $this->pos = $pos_122; - $_125 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_125->expand("&&") ) ) !== FALSE) { + $result = $res_151; + $this->pos = $pos_151; + if (( $subres = $this->literal( '&&' ) ) !== FALSE) { $result["text"] .= $subres; - $_127 = TRUE; break; + $_154 = TRUE; break; } - $result = $res_122; - $this->pos = $pos_122; - $_127 = FALSE; break; + $result = $res_151; + $this->pos = $pos_151; + $_154 = FALSE; break; } while(0); - if( $_127 === TRUE ) { - return $this->finalise( "BooleanOperator", $result ); - } - if( $_127 === FALSE) { return FALSE; } + if( $_154 === TRUE ) { return $this->finalise($result); } + if( $_154 === FALSE) { return FALSE; } } /* IfArgument: :IfArgumentPortion ( < :BooleanOperator < :IfArgumentPortion )* */ - function match_IfArgument ($substack = array()) { - $result = $this->construct( "IfArgument" ); - $_136 = NULL; + protected $match_IfArgument_typestack = array('IfArgument'); + function match_IfArgument ($stack = array()) { + $matchrule = "IfArgument"; $result = $this->construct($matchrule, $matchrule, null); + $_163 = NULL; do { - $key = "IfArgumentPortion"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgumentPortion(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'IfArgumentPortion'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "IfArgumentPortion" ); } - else { $_136 = FALSE; break; } + else { $_163 = FALSE; break; } while (true) { - $res_135 = $result; - $pos_135 = $this->pos; - $_134 = NULL; + $res_162 = $result; + $pos_162 = $this->pos; + $_161 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "BooleanOperator"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BooleanOperator(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'BooleanOperator'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BooleanOperator" ); } - else { $_134 = FALSE; break; } + else { $_161 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "IfArgumentPortion"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgumentPortion(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'IfArgumentPortion'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "IfArgumentPortion" ); } - else { $_134 = FALSE; break; } - $_134 = TRUE; break; + else { $_161 = FALSE; break; } + $_161 = TRUE; break; } while(0); - if( $_134 === FALSE) { - $result = $res_135; - $this->pos = $pos_135; - unset( $res_135 ); - unset( $pos_135 ); + if( $_161 === FALSE) { + $result = $res_162; + $this->pos = $pos_162; + unset( $res_162 ); + unset( $pos_162 ); break; } } - $_136 = TRUE; break; + $_163 = TRUE; break; } while(0); - if( $_136 === TRUE ) { - return $this->finalise( "IfArgument", $result ); - } - if( $_136 === FALSE) { return FALSE; } + if( $_163 === TRUE ) { return $this->finalise($result); } + if( $_163 === FALSE) { return FALSE; } } - function IfArgument__construct(&$res){ - $res['php'] = ''; - } function IfArgument_IfArgumentPortion(&$res, $sub) { $res['php'] .= $sub['php']; } @@ -982,177 +1172,161 @@ class SSTemplateParser extends Parser { $res['php'] .= $sub['text']; } - /* IfPart: '<%' < 'if' [ :IfArgument > '%>' :Template? */ - function match_IfPart ($substack = array()) { - $result = $this->construct( "IfPart" ); - $_149 = NULL; + /* IfPart: '<%' < 'if' [ :IfArgument > '%>' Template:$TemplateMatcher? */ + protected $match_IfPart_typestack = array('IfPart'); + function match_IfPart ($stack = array()) { + $matchrule = "IfPart"; $result = $this->construct($matchrule, $matchrule, null); + $_173 = NULL; do { - $_138 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_138->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_149 = FALSE; break; } + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_173 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_141 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_141->expand('if') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_149 = FALSE; break; } + if (( $subres = $this->literal( 'if' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_173 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_149 = FALSE; break; } - $key = "IfArgument"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgument(array_merge($substack, array($result))) ) ); + else { $_173 = FALSE; break; } + $matcher = 'match_'.'IfArgument'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "IfArgument" ); } - else { $_149 = FALSE; break; } + else { $_173 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_146 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_146->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_149 = FALSE; break; } - $res_148 = $result; - $pos_148 = $this->pos; - $key = "Template"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_173 = FALSE; break; } + $res_172 = $result; + $pos_172 = $this->pos; + $matcher = 'match_'.$this->expression($result, $stack, 'TemplateMatcher'); $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Template" ); } else { - $result = $res_148; - $this->pos = $pos_148; - unset( $res_148 ); - unset( $pos_148 ); + $result = $res_172; + $this->pos = $pos_172; + unset( $res_172 ); + unset( $pos_172 ); } - $_149 = TRUE; break; - } - while(0); - if( $_149 === TRUE ) { - return $this->finalise( "IfPart", $result ); - } - if( $_149 === FALSE) { return FALSE; } - } - - - /* ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' :Template */ - function match_ElseIfPart ($substack = array()) { - $result = $this->construct( "ElseIfPart" ); - $_162 = NULL; - do { - $_151 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_151->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_162 = FALSE; break; } - if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_154 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_154->expand('else_if') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_162 = FALSE; break; } - if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_162 = FALSE; break; } - $key = "IfArgument"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfArgument(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres, "IfArgument" ); - } - else { $_162 = FALSE; break; } - if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_159 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_159->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_162 = FALSE; break; } - $key = "Template"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres, "Template" ); - } - else { $_162 = FALSE; break; } - $_162 = TRUE; break; - } - while(0); - if( $_162 === TRUE ) { - return $this->finalise( "ElseIfPart", $result ); - } - if( $_162 === FALSE) { return FALSE; } - } - - - /* ElsePart: '<%' < 'else' > '%>' :Template */ - function match_ElsePart ($substack = array()) { - $result = $this->construct( "ElsePart" ); - $_173 = NULL; - do { - $_164 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_164->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_173 = FALSE; break; } - if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_167 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_167->expand('else') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_173 = FALSE; break; } - if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_170 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_170->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_173 = FALSE; break; } - $key = "Template"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres, "Template" ); - } - else { $_173 = FALSE; break; } $_173 = TRUE; break; } while(0); - if( $_173 === TRUE ) { - return $this->finalise( "ElsePart", $result ); - } + if( $_173 === TRUE ) { return $this->finalise($result); } if( $_173 === FALSE) { return FALSE; } } - /* If: IfPart ElseIfPart* ElsePart? '<%' < 'end_if' > '%>' */ - function match_If ($substack = array()) { - $result = $this->construct( "If" ); - $_186 = NULL; + /* ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' Template:$TemplateMatcher */ + protected $match_ElseIfPart_typestack = array('ElseIfPart'); + function match_ElseIfPart ($stack = array()) { + $matchrule = "ElseIfPart"; $result = $this->construct($matchrule, $matchrule, null); + $_183 = NULL; do { - $key = "IfPart"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_IfPart(array_merge($substack, array($result))) ) ); + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_183 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (( $subres = $this->literal( 'else_if' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_183 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_183 = FALSE; break; } + $matcher = 'match_'.'IfArgument'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "IfArgument" ); + } + else { $_183 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_183 = FALSE; break; } + $matcher = 'match_'.$this->expression($result, $stack, 'TemplateMatcher'); $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Template" ); + } + else { $_183 = FALSE; break; } + $_183 = TRUE; break; + } + while(0); + if( $_183 === TRUE ) { return $this->finalise($result); } + if( $_183 === FALSE) { return FALSE; } + } + + + /* ElsePart: '<%' < 'else' > '%>' Template:$TemplateMatcher */ + protected $match_ElsePart_typestack = array('ElsePart'); + function match_ElsePart ($stack = array()) { + $matchrule = "ElsePart"; $result = $this->construct($matchrule, $matchrule, null); + $_191 = NULL; + do { + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_191 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (( $subres = $this->literal( 'else' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_191 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_191 = FALSE; break; } + $matcher = 'match_'.$this->expression($result, $stack, 'TemplateMatcher'); $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Template" ); + } + else { $_191 = FALSE; break; } + $_191 = TRUE; break; + } + while(0); + if( $_191 === TRUE ) { return $this->finalise($result); } + if( $_191 === FALSE) { return FALSE; } + } + + + /* If: IfPart ElseIfPart* ElsePart? '<%' < 'end_if' > '%>' */ + protected $match_If_typestack = array('If'); + function match_If ($stack = array()) { + $matchrule = "If"; $result = $this->construct($matchrule, $matchrule, null); + $_201 = NULL; + do { + $matcher = 'match_'.'IfPart'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_186 = FALSE; break; } + else { $_201 = FALSE; break; } while (true) { - $res_176 = $result; - $pos_176 = $this->pos; - $key = "ElseIfPart"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ElseIfPart(array_merge($substack, array($result))) ) ); + $res_194 = $result; + $pos_194 = $this->pos; + $matcher = 'match_'.'ElseIfPart'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } else { - $result = $res_176; - $this->pos = $pos_176; - unset( $res_176 ); - unset( $pos_176 ); + $result = $res_194; + $this->pos = $pos_194; + unset( $res_194 ); + unset( $pos_194 ); break; } } - $res_177 = $result; - $pos_177 = $this->pos; - $key = "ElsePart"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ElsePart(array_merge($substack, array($result))) ) ); + $res_195 = $result; + $pos_195 = $this->pos; + $matcher = 'match_'.'ElsePart'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } else { - $result = $res_177; - $this->pos = $pos_177; - unset( $res_177 ); - unset( $pos_177 ); + $result = $res_195; + $this->pos = $pos_195; + unset( $res_195 ); + unset( $pos_195 ); } - $_178 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_178->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_186 = FALSE; break; } + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_201 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_181 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_181->expand('end_if') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_186 = FALSE; break; } + if (( $subres = $this->literal( 'end_if' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_201 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_184 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_184->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_186 = FALSE; break; } - $_186 = TRUE; break; + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_201 = FALSE; break; } + $_201 = TRUE; break; } while(0); - if( $_186 === TRUE ) { - return $this->finalise( "If", $result ); - } - if( $_186 === FALSE) { return FALSE; } + if( $_201 === TRUE ) { return $this->finalise($result); } + if( $_201 === FALSE) { return FALSE; } } @@ -1179,70 +1353,64 @@ class SSTemplateParser extends Parser { } /* Require: '<%' < 'require' [ Call:(Method:Word "(" < :CallArguments > ")") > '%>' */ - function match_Require ($substack = array()) { - $result = $this->construct( "Require" ); - $_206 = NULL; + protected $match_Require_typestack = array('Require'); + function match_Require ($stack = array()) { + $matchrule = "Require"; $result = $this->construct($matchrule, $matchrule, null); + $_217 = NULL; do { - $_188 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_188->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_206 = FALSE; break; } + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_217 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_191 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_191->expand('require') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_206 = FALSE; break; } + if (( $subres = $this->literal( 'require' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_217 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_206 = FALSE; break; } - $substack[] = $result; - $result = $this->construct( "Call" ); - $_200 = NULL; + else { $_217 = FALSE; break; } + $stack[] = $result; $result = $this->construct( $matchrule, "Call" ); + $_213 = NULL; do { - $key = "Word"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Word'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Method" ); } - else { $_200 = FALSE; break; } - if (substr($this->string,$this->pos,1) == "(") { + else { $_213 = FALSE; break; } + if (substr($this->string,$this->pos,1) == '(') { $this->pos += 1; - $result["text"] .= "("; + $result["text"] .= '('; } - else { $_200 = FALSE; break; } + else { $_213 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "CallArguments"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_CallArguments(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'CallArguments'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "CallArguments" ); } - else { $_200 = FALSE; break; } + else { $_213 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - if (substr($this->string,$this->pos,1) == ")") { + if (substr($this->string,$this->pos,1) == ')') { $this->pos += 1; - $result["text"] .= ")"; + $result["text"] .= ')'; } - else { $_200 = FALSE; break; } - $_200 = TRUE; break; + else { $_213 = FALSE; break; } + $_213 = TRUE; break; } while(0); - if( $_200 === TRUE ) { - $subres = $result ; - $result = array_pop( $substack ) ; + if( $_213 === TRUE ) { + $subres = $result; $result = array_pop($stack); $this->store( $result, $subres, 'Call' ); } - if( $_200 === FALSE) { - $result = array_pop( $substack ) ; - $_206 = FALSE; break; + if( $_213 === FALSE) { + $result = array_pop($stack); + $_217 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_204 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_204->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_206 = FALSE; break; } - $_206 = TRUE; break; + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_217 = FALSE; break; } + $_217 = TRUE; break; } while(0); - if( $_206 === TRUE ) { - return $this->finalise( "Require", $result ); - } - if( $_206 === FALSE) { return FALSE; } + if( $_217 === TRUE ) { return $this->finalise($result); } + if( $_217 === FALSE) { return FALSE; } } @@ -1251,62 +1419,1066 @@ class SSTemplateParser extends Parser { $res['php'] = "Requirements::".$sub['Method']['text'].'('.$sub['CallArguments']['php'].');'; } - /* OldTPart: "_t" < "(" < QuotedString (< "," < CallArguments)? > ")" */ - function match_OldTPart ($substack = array()) { - $result = $this->construct( "OldTPart" ); - $_222 = NULL; + + /* CacheBlockArgument: + !( "if " | "unless " ) + ( + :DollarMarkedLookup | + :QuotedString | + :Lookup + ) */ + protected $match_CacheBlockArgument_typestack = array('CacheBlockArgument'); + function match_CacheBlockArgument ($stack = array()) { + $matchrule = "CacheBlockArgument"; $result = $this->construct($matchrule, $matchrule, null); + $_237 = NULL; do { - $_208 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_208->expand("_t") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_222 = FALSE; break; } - if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - if (substr($this->string,$this->pos,1) == "(") { - $this->pos += 1; - $result["text"] .= "("; - } - else { $_222 = FALSE; break; } - if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "QuotedString"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_QuotedString(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_222 = FALSE; break; } - $res_219 = $result; - $pos_219 = $this->pos; - $_218 = NULL; + $res_225 = $result; + $pos_225 = $this->pos; + $_224 = NULL; do { - if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - if (substr($this->string,$this->pos,1) == ",") { - $this->pos += 1; - $result["text"] .= ","; + $_222 = NULL; + do { + $res_219 = $result; + $pos_219 = $this->pos; + if (( $subres = $this->literal( 'if ' ) ) !== FALSE) { + $result["text"] .= $subres; + $_222 = TRUE; break; + } + $result = $res_219; + $this->pos = $pos_219; + if (( $subres = $this->literal( 'unless ' ) ) !== FALSE) { + $result["text"] .= $subres; + $_222 = TRUE; break; + } + $result = $res_219; + $this->pos = $pos_219; + $_222 = FALSE; break; } - else { $_218 = FALSE; break; } - if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "CallArguments"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_CallArguments(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_218 = FALSE; break; } - $_218 = TRUE; break; + while(0); + if( $_222 === FALSE) { $_224 = FALSE; break; } + $_224 = TRUE; break; } while(0); - if( $_218 === FALSE) { - $result = $res_219; - $this->pos = $pos_219; - unset( $res_219 ); - unset( $pos_219 ); + if( $_224 === TRUE ) { + $result = $res_225; + $this->pos = $pos_225; + $_237 = FALSE; break; } - if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - if (substr($this->string,$this->pos,1) == ")") { - $this->pos += 1; - $result["text"] .= ")"; + if( $_224 === FALSE) { + $result = $res_225; + $this->pos = $pos_225; } - else { $_222 = FALSE; break; } - $_222 = TRUE; break; + $_235 = NULL; + do { + $_233 = NULL; + do { + $res_226 = $result; + $pos_226 = $this->pos; + $matcher = 'match_'.'DollarMarkedLookup'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "DollarMarkedLookup" ); + $_233 = TRUE; break; + } + $result = $res_226; + $this->pos = $pos_226; + $_231 = NULL; + do { + $res_228 = $result; + $pos_228 = $this->pos; + $matcher = 'match_'.'QuotedString'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "QuotedString" ); + $_231 = TRUE; break; + } + $result = $res_228; + $this->pos = $pos_228; + $matcher = 'match_'.'Lookup'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Lookup" ); + $_231 = TRUE; break; + } + $result = $res_228; + $this->pos = $pos_228; + $_231 = FALSE; break; + } + while(0); + if( $_231 === TRUE ) { $_233 = TRUE; break; } + $result = $res_226; + $this->pos = $pos_226; + $_233 = FALSE; break; + } + while(0); + if( $_233 === FALSE) { $_235 = FALSE; break; } + $_235 = TRUE; break; + } + while(0); + if( $_235 === FALSE) { $_237 = FALSE; break; } + $_237 = TRUE; break; } while(0); - if( $_222 === TRUE ) { - return $this->finalise( "OldTPart", $result ); + if( $_237 === TRUE ) { return $this->finalise($result); } + if( $_237 === FALSE) { return FALSE; } + } + + + + function CacheBlockArgument_DollarMarkedLookup(&$res, $sub) { + $res['php'] = $sub['Lookup']['php']; + } + + function CacheBlockArgument_QuotedString(&$res, $sub) { + $res['php'] = "'" . str_replace("'", "\\'", $sub['String']['text']) . "'"; + } + + function CacheBlockArgument_Lookup(&$res, $sub) { + $res['php'] = $sub['php']; + } + + /* CacheBlockArguments: CacheBlockArgument ( < "," < CacheBlockArgument )* */ + protected $match_CacheBlockArguments_typestack = array('CacheBlockArguments'); + function match_CacheBlockArguments ($stack = array()) { + $matchrule = "CacheBlockArguments"; $result = $this->construct($matchrule, $matchrule, null); + $_246 = NULL; + do { + $matcher = 'match_'.'CacheBlockArgument'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_246 = FALSE; break; } + while (true) { + $res_245 = $result; + $pos_245 = $this->pos; + $_244 = NULL; + do { + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == ',') { + $this->pos += 1; + $result["text"] .= ','; + } + else { $_244 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $matcher = 'match_'.'CacheBlockArgument'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_244 = FALSE; break; } + $_244 = TRUE; break; + } + while(0); + if( $_244 === FALSE) { + $result = $res_245; + $this->pos = $pos_245; + unset( $res_245 ); + unset( $pos_245 ); + break; + } + } + $_246 = TRUE; break; } - if( $_222 === FALSE) { return FALSE; } + while(0); + if( $_246 === TRUE ) { return $this->finalise($result); } + if( $_246 === FALSE) { return FALSE; } + } + + + + function CacheBlockArguments_CacheBlockArgument(&$res, $sub) { + if (!empty($res['php'])) $res['php'] .= ".'_'."; + else $res['php'] = ''; + + $res['php'] .= str_replace('$$FINAL', 'XML_val', $sub['php']); + } + + /* CacheBlockTemplate: (Comment | If | Require | OldI18NTag | ClosedBlock | OpenBlock | MalformedBlock | Injection | Text)+ */ + protected $match_CacheBlockTemplate_typestack = array('CacheBlockTemplate','Template'); + function match_CacheBlockTemplate ($stack = array()) { + $matchrule = "CacheBlockTemplate"; $result = $this->construct($matchrule, $matchrule, array('TemplateMatcher' => 'CacheRestrictedTemplate')); + $count = 0; + while (true) { + $res_282 = $result; + $pos_282 = $this->pos; + $_281 = NULL; + do { + $_279 = NULL; + do { + $res_248 = $result; + $pos_248 = $this->pos; + $matcher = 'match_'.'Comment'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_279 = TRUE; break; + } + $result = $res_248; + $this->pos = $pos_248; + $_277 = NULL; + do { + $res_250 = $result; + $pos_250 = $this->pos; + $matcher = 'match_'.'If'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_277 = TRUE; break; + } + $result = $res_250; + $this->pos = $pos_250; + $_275 = NULL; + do { + $res_252 = $result; + $pos_252 = $this->pos; + $matcher = 'match_'.'Require'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_275 = TRUE; break; + } + $result = $res_252; + $this->pos = $pos_252; + $_273 = NULL; + do { + $res_254 = $result; + $pos_254 = $this->pos; + $matcher = 'match_'.'OldI18NTag'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_273 = TRUE; break; + } + $result = $res_254; + $this->pos = $pos_254; + $_271 = NULL; + do { + $res_256 = $result; + $pos_256 = $this->pos; + $matcher = 'match_'.'ClosedBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_271 = TRUE; break; + } + $result = $res_256; + $this->pos = $pos_256; + $_269 = NULL; + do { + $res_258 = $result; + $pos_258 = $this->pos; + $matcher = 'match_'.'OpenBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_269 = TRUE; break; + } + $result = $res_258; + $this->pos = $pos_258; + $_267 = NULL; + do { + $res_260 = $result; + $pos_260 = $this->pos; + $matcher = 'match_'.'MalformedBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_267 = TRUE; break; + } + $result = $res_260; + $this->pos = $pos_260; + $_265 = NULL; + do { + $res_262 = $result; + $pos_262 = $this->pos; + $matcher = 'match_'.'Injection'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_265 = TRUE; break; + } + $result = $res_262; + $this->pos = $pos_262; + $matcher = 'match_'.'Text'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_265 = TRUE; break; + } + $result = $res_262; + $this->pos = $pos_262; + $_265 = FALSE; break; + } + while(0); + if( $_265 === TRUE ) { $_267 = TRUE; break; } + $result = $res_260; + $this->pos = $pos_260; + $_267 = FALSE; break; + } + while(0); + if( $_267 === TRUE ) { $_269 = TRUE; break; } + $result = $res_258; + $this->pos = $pos_258; + $_269 = FALSE; break; + } + while(0); + if( $_269 === TRUE ) { $_271 = TRUE; break; } + $result = $res_256; + $this->pos = $pos_256; + $_271 = FALSE; break; + } + while(0); + if( $_271 === TRUE ) { $_273 = TRUE; break; } + $result = $res_254; + $this->pos = $pos_254; + $_273 = FALSE; break; + } + while(0); + if( $_273 === TRUE ) { $_275 = TRUE; break; } + $result = $res_252; + $this->pos = $pos_252; + $_275 = FALSE; break; + } + while(0); + if( $_275 === TRUE ) { $_277 = TRUE; break; } + $result = $res_250; + $this->pos = $pos_250; + $_277 = FALSE; break; + } + while(0); + if( $_277 === TRUE ) { $_279 = TRUE; break; } + $result = $res_248; + $this->pos = $pos_248; + $_279 = FALSE; break; + } + while(0); + if( $_279 === FALSE) { $_281 = FALSE; break; } + $_281 = TRUE; break; + } + while(0); + if( $_281 === FALSE) { + $result = $res_282; + $this->pos = $pos_282; + unset( $res_282 ); + unset( $pos_282 ); + break; + } + $count += 1; + } + if ($count > 0) { return $this->finalise($result); } + else { return FALSE; } + } + + + + + /* UncachedBlock: + '<%' < "uncached" < CacheBlockArguments? ( < Conditional:("if"|"unless") > Condition:IfArgument )? > '%>' + Template:$TemplateMatcher? + '<%' < 'end_' ("uncached"|"cached"|"cacheblock") > '%>' */ + protected $match_UncachedBlock_typestack = array('UncachedBlock'); + function match_UncachedBlock ($stack = array()) { + $matchrule = "UncachedBlock"; $result = $this->construct($matchrule, $matchrule, null); + $_319 = NULL; + do { + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_319 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (( $subres = $this->literal( 'uncached' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_319 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $res_287 = $result; + $pos_287 = $this->pos; + $matcher = 'match_'.'CacheBlockArguments'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { + $result = $res_287; + $this->pos = $pos_287; + unset( $res_287 ); + unset( $pos_287 ); + } + $res_299 = $result; + $pos_299 = $this->pos; + $_298 = NULL; + do { + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $stack[] = $result; $result = $this->construct( $matchrule, "Conditional" ); + $_294 = NULL; + do { + $_292 = NULL; + do { + $res_289 = $result; + $pos_289 = $this->pos; + if (( $subres = $this->literal( 'if' ) ) !== FALSE) { + $result["text"] .= $subres; + $_292 = TRUE; break; + } + $result = $res_289; + $this->pos = $pos_289; + if (( $subres = $this->literal( 'unless' ) ) !== FALSE) { + $result["text"] .= $subres; + $_292 = TRUE; break; + } + $result = $res_289; + $this->pos = $pos_289; + $_292 = FALSE; break; + } + while(0); + if( $_292 === FALSE) { $_294 = FALSE; break; } + $_294 = TRUE; break; + } + while(0); + if( $_294 === TRUE ) { + $subres = $result; $result = array_pop($stack); + $this->store( $result, $subres, 'Conditional' ); + } + if( $_294 === FALSE) { + $result = array_pop($stack); + $_298 = FALSE; break; + } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $matcher = 'match_'.'IfArgument'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Condition" ); + } + else { $_298 = FALSE; break; } + $_298 = TRUE; break; + } + while(0); + if( $_298 === FALSE) { + $result = $res_299; + $this->pos = $pos_299; + unset( $res_299 ); + unset( $pos_299 ); + } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_319 = FALSE; break; } + $res_302 = $result; + $pos_302 = $this->pos; + $matcher = 'match_'.$this->expression($result, $stack, 'TemplateMatcher'); $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Template" ); + } + else { + $result = $res_302; + $this->pos = $pos_302; + unset( $res_302 ); + unset( $pos_302 ); + } + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_319 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (( $subres = $this->literal( 'end_' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_319 = FALSE; break; } + $_315 = NULL; + do { + $_313 = NULL; + do { + $res_306 = $result; + $pos_306 = $this->pos; + if (( $subres = $this->literal( 'uncached' ) ) !== FALSE) { + $result["text"] .= $subres; + $_313 = TRUE; break; + } + $result = $res_306; + $this->pos = $pos_306; + $_311 = NULL; + do { + $res_308 = $result; + $pos_308 = $this->pos; + if (( $subres = $this->literal( 'cached' ) ) !== FALSE) { + $result["text"] .= $subres; + $_311 = TRUE; break; + } + $result = $res_308; + $this->pos = $pos_308; + if (( $subres = $this->literal( 'cacheblock' ) ) !== FALSE) { + $result["text"] .= $subres; + $_311 = TRUE; break; + } + $result = $res_308; + $this->pos = $pos_308; + $_311 = FALSE; break; + } + while(0); + if( $_311 === TRUE ) { $_313 = TRUE; break; } + $result = $res_306; + $this->pos = $pos_306; + $_313 = FALSE; break; + } + while(0); + if( $_313 === FALSE) { $_315 = FALSE; break; } + $_315 = TRUE; break; + } + while(0); + if( $_315 === FALSE) { $_319 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_319 = FALSE; break; } + $_319 = TRUE; break; + } + while(0); + if( $_319 === TRUE ) { return $this->finalise($result); } + if( $_319 === FALSE) { return FALSE; } + } + + + + function UncachedBlock_Template(&$res, $sub){ + $res['php'] = $sub['php']; + } + + /* CacheRestrictedTemplate: (Comment | If | Require | CacheBlock | UncachedBlock | OldI18NTag | ClosedBlock | OpenBlock | MalformedBlock | Injection | Text)+ */ + protected $match_CacheRestrictedTemplate_typestack = array('CacheRestrictedTemplate','Template'); + function match_CacheRestrictedTemplate ($stack = array()) { + $matchrule = "CacheRestrictedTemplate"; $result = $this->construct($matchrule, $matchrule, null); + $count = 0; + while (true) { + $res_363 = $result; + $pos_363 = $this->pos; + $_362 = NULL; + do { + $_360 = NULL; + do { + $res_321 = $result; + $pos_321 = $this->pos; + $matcher = 'match_'.'Comment'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_360 = TRUE; break; + } + $result = $res_321; + $this->pos = $pos_321; + $_358 = NULL; + do { + $res_323 = $result; + $pos_323 = $this->pos; + $matcher = 'match_'.'If'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_358 = TRUE; break; + } + $result = $res_323; + $this->pos = $pos_323; + $_356 = NULL; + do { + $res_325 = $result; + $pos_325 = $this->pos; + $matcher = 'match_'.'Require'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_356 = TRUE; break; + } + $result = $res_325; + $this->pos = $pos_325; + $_354 = NULL; + do { + $res_327 = $result; + $pos_327 = $this->pos; + $matcher = 'match_'.'CacheBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_354 = TRUE; break; + } + $result = $res_327; + $this->pos = $pos_327; + $_352 = NULL; + do { + $res_329 = $result; + $pos_329 = $this->pos; + $matcher = 'match_'.'UncachedBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_352 = TRUE; break; + } + $result = $res_329; + $this->pos = $pos_329; + $_350 = NULL; + do { + $res_331 = $result; + $pos_331 = $this->pos; + $matcher = 'match_'.'OldI18NTag'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_350 = TRUE; break; + } + $result = $res_331; + $this->pos = $pos_331; + $_348 = NULL; + do { + $res_333 = $result; + $pos_333 = $this->pos; + $matcher = 'match_'.'ClosedBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_348 = TRUE; break; + } + $result = $res_333; + $this->pos = $pos_333; + $_346 = NULL; + do { + $res_335 = $result; + $pos_335 = $this->pos; + $matcher = 'match_'.'OpenBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_346 = TRUE; break; + } + $result = $res_335; + $this->pos = $pos_335; + $_344 = NULL; + do { + $res_337 = $result; + $pos_337 = $this->pos; + $matcher = 'match_'.'MalformedBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_344 = TRUE; break; + } + $result = $res_337; + $this->pos = $pos_337; + $_342 = NULL; + do { + $res_339 = $result; + $pos_339 = $this->pos; + $matcher = 'match_'.'Injection'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_342 = TRUE; break; + } + $result = $res_339; + $this->pos = $pos_339; + $matcher = 'match_'.'Text'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_342 = TRUE; break; + } + $result = $res_339; + $this->pos = $pos_339; + $_342 = FALSE; break; + } + while(0); + if( $_342 === TRUE ) { $_344 = TRUE; break; } + $result = $res_337; + $this->pos = $pos_337; + $_344 = FALSE; break; + } + while(0); + if( $_344 === TRUE ) { $_346 = TRUE; break; } + $result = $res_335; + $this->pos = $pos_335; + $_346 = FALSE; break; + } + while(0); + if( $_346 === TRUE ) { $_348 = TRUE; break; } + $result = $res_333; + $this->pos = $pos_333; + $_348 = FALSE; break; + } + while(0); + if( $_348 === TRUE ) { $_350 = TRUE; break; } + $result = $res_331; + $this->pos = $pos_331; + $_350 = FALSE; break; + } + while(0); + if( $_350 === TRUE ) { $_352 = TRUE; break; } + $result = $res_329; + $this->pos = $pos_329; + $_352 = FALSE; break; + } + while(0); + if( $_352 === TRUE ) { $_354 = TRUE; break; } + $result = $res_327; + $this->pos = $pos_327; + $_354 = FALSE; break; + } + while(0); + if( $_354 === TRUE ) { $_356 = TRUE; break; } + $result = $res_325; + $this->pos = $pos_325; + $_356 = FALSE; break; + } + while(0); + if( $_356 === TRUE ) { $_358 = TRUE; break; } + $result = $res_323; + $this->pos = $pos_323; + $_358 = FALSE; break; + } + while(0); + if( $_358 === TRUE ) { $_360 = TRUE; break; } + $result = $res_321; + $this->pos = $pos_321; + $_360 = FALSE; break; + } + while(0); + if( $_360 === FALSE) { $_362 = FALSE; break; } + $_362 = TRUE; break; + } + while(0); + if( $_362 === FALSE) { + $result = $res_363; + $this->pos = $pos_363; + unset( $res_363 ); + unset( $pos_363 ); + break; + } + $count += 1; + } + if ($count > 0) { return $this->finalise($result); } + else { return FALSE; } + } + + + + function CacheRestrictedTemplate_CacheBlock(&$res, $sub) { + throw new SSTemplateParseException('You cant have cache blocks nested within with, loop or control blocks that are within cache blocks', $this); + } + + function CacheRestrictedTemplate_UncachedBlock(&$res, $sub) { + throw new SSTemplateParseException('You cant have uncache blocks nested within with, loop or control blocks that are within cache blocks', $this); + } + + /* CacheBlock: + '<%' < CacheTag:("cached"|"cacheblock") < (CacheBlockArguments)? ( < Conditional:("if"|"unless") > Condition:IfArgument )? > '%>' + (CacheBlock | UncachedBlock | CacheBlockTemplate)* + '<%' < 'end_' ("cached"|"uncached"|"cacheblock") > '%>' */ + protected $match_CacheBlock_typestack = array('CacheBlock'); + function match_CacheBlock ($stack = array()) { + $matchrule = "CacheBlock"; $result = $this->construct($matchrule, $matchrule, null); + $_418 = NULL; + do { + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_418 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $stack[] = $result; $result = $this->construct( $matchrule, "CacheTag" ); + $_371 = NULL; + do { + $_369 = NULL; + do { + $res_366 = $result; + $pos_366 = $this->pos; + if (( $subres = $this->literal( 'cached' ) ) !== FALSE) { + $result["text"] .= $subres; + $_369 = TRUE; break; + } + $result = $res_366; + $this->pos = $pos_366; + if (( $subres = $this->literal( 'cacheblock' ) ) !== FALSE) { + $result["text"] .= $subres; + $_369 = TRUE; break; + } + $result = $res_366; + $this->pos = $pos_366; + $_369 = FALSE; break; + } + while(0); + if( $_369 === FALSE) { $_371 = FALSE; break; } + $_371 = TRUE; break; + } + while(0); + if( $_371 === TRUE ) { + $subres = $result; $result = array_pop($stack); + $this->store( $result, $subres, 'CacheTag' ); + } + if( $_371 === FALSE) { + $result = array_pop($stack); + $_418 = FALSE; break; + } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $res_376 = $result; + $pos_376 = $this->pos; + $_375 = NULL; + do { + $matcher = 'match_'.'CacheBlockArguments'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_375 = FALSE; break; } + $_375 = TRUE; break; + } + while(0); + if( $_375 === FALSE) { + $result = $res_376; + $this->pos = $pos_376; + unset( $res_376 ); + unset( $pos_376 ); + } + $res_388 = $result; + $pos_388 = $this->pos; + $_387 = NULL; + do { + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $stack[] = $result; $result = $this->construct( $matchrule, "Conditional" ); + $_383 = NULL; + do { + $_381 = NULL; + do { + $res_378 = $result; + $pos_378 = $this->pos; + if (( $subres = $this->literal( 'if' ) ) !== FALSE) { + $result["text"] .= $subres; + $_381 = TRUE; break; + } + $result = $res_378; + $this->pos = $pos_378; + if (( $subres = $this->literal( 'unless' ) ) !== FALSE) { + $result["text"] .= $subres; + $_381 = TRUE; break; + } + $result = $res_378; + $this->pos = $pos_378; + $_381 = FALSE; break; + } + while(0); + if( $_381 === FALSE) { $_383 = FALSE; break; } + $_383 = TRUE; break; + } + while(0); + if( $_383 === TRUE ) { + $subres = $result; $result = array_pop($stack); + $this->store( $result, $subres, 'Conditional' ); + } + if( $_383 === FALSE) { + $result = array_pop($stack); + $_387 = FALSE; break; + } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $matcher = 'match_'.'IfArgument'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Condition" ); + } + else { $_387 = FALSE; break; } + $_387 = TRUE; break; + } + while(0); + if( $_387 === FALSE) { + $result = $res_388; + $this->pos = $pos_388; + unset( $res_388 ); + unset( $pos_388 ); + } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_418 = FALSE; break; } + while (true) { + $res_401 = $result; + $pos_401 = $this->pos; + $_400 = NULL; + do { + $_398 = NULL; + do { + $res_391 = $result; + $pos_391 = $this->pos; + $matcher = 'match_'.'CacheBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_398 = TRUE; break; + } + $result = $res_391; + $this->pos = $pos_391; + $_396 = NULL; + do { + $res_393 = $result; + $pos_393 = $this->pos; + $matcher = 'match_'.'UncachedBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_396 = TRUE; break; + } + $result = $res_393; + $this->pos = $pos_393; + $matcher = 'match_'.'CacheBlockTemplate'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_396 = TRUE; break; + } + $result = $res_393; + $this->pos = $pos_393; + $_396 = FALSE; break; + } + while(0); + if( $_396 === TRUE ) { $_398 = TRUE; break; } + $result = $res_391; + $this->pos = $pos_391; + $_398 = FALSE; break; + } + while(0); + if( $_398 === FALSE) { $_400 = FALSE; break; } + $_400 = TRUE; break; + } + while(0); + if( $_400 === FALSE) { + $result = $res_401; + $this->pos = $pos_401; + unset( $res_401 ); + unset( $pos_401 ); + break; + } + } + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_418 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (( $subres = $this->literal( 'end_' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_418 = FALSE; break; } + $_414 = NULL; + do { + $_412 = NULL; + do { + $res_405 = $result; + $pos_405 = $this->pos; + if (( $subres = $this->literal( 'cached' ) ) !== FALSE) { + $result["text"] .= $subres; + $_412 = TRUE; break; + } + $result = $res_405; + $this->pos = $pos_405; + $_410 = NULL; + do { + $res_407 = $result; + $pos_407 = $this->pos; + if (( $subres = $this->literal( 'uncached' ) ) !== FALSE) { + $result["text"] .= $subres; + $_410 = TRUE; break; + } + $result = $res_407; + $this->pos = $pos_407; + if (( $subres = $this->literal( 'cacheblock' ) ) !== FALSE) { + $result["text"] .= $subres; + $_410 = TRUE; break; + } + $result = $res_407; + $this->pos = $pos_407; + $_410 = FALSE; break; + } + while(0); + if( $_410 === TRUE ) { $_412 = TRUE; break; } + $result = $res_405; + $this->pos = $pos_405; + $_412 = FALSE; break; + } + while(0); + if( $_412 === FALSE) { $_414 = FALSE; break; } + $_414 = TRUE; break; + } + while(0); + if( $_414 === FALSE) { $_418 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_418 = FALSE; break; } + $_418 = TRUE; break; + } + while(0); + if( $_418 === TRUE ) { return $this->finalise($result); } + if( $_418 === FALSE) { return FALSE; } + } + + + + function CacheBlock__construct(&$res){ + $res['subblocks'] = 0; + } + + function CacheBlock_CacheBlockArguments(&$res, $sub){ + $res['key'] = !empty($sub['php']) ? $sub['php'] : ''; + } + + function CacheBlock_Condition(&$res, $sub){ + $res['condition'] = ($res['Conditional']['text'] == 'if' ? '(' : '!(') . $sub['php'] . ') && '; + } + + function CacheBlock_CacheBlock(&$res, $sub){ + $res['php'] .= $sub['php']; + } + + function CacheBlock_UncachedBlock(&$res, $sub){ + $res['php'] .= $sub['php']; + } + + function CacheBlock_CacheBlockTemplate(&$res, $sub){ + // Get the block counter + $block = ++$res['subblocks']; + // Build the key for this block from the passed cache key, the block index, and the sha hash of the template itself + $key = "'" . sha1($sub['php']) . (isset($res['key']) && $res['key'] ? "_'.sha1(".$res['key'].")" : "'") . ".'_$block'"; + // Get any condition + $condition = isset($res['condition']) ? $res['condition'] : ''; + + $res['php'] .= 'if ('.$condition.'($partial = $cache->load('.$key.'))) $val .= $partial;' . PHP_EOL; + $res['php'] .= 'else { $oldval = $val; $val = "";' . PHP_EOL; + $res['php'] .= $sub['php'] . PHP_EOL; + $res['php'] .= $condition . ' $cache->save($val); $val = $oldval . $val;' . PHP_EOL; + $res['php'] .= '}'; + } + + /* OldTPart: "_t" < "(" < QuotedString (< "," < CallArguments)? > ")" */ + protected $match_OldTPart_typestack = array('OldTPart'); + function match_OldTPart ($stack = array()) { + $matchrule = "OldTPart"; $result = $this->construct($matchrule, $matchrule, null); + $_433 = NULL; + do { + if (( $subres = $this->literal( '_t' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_433 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == '(') { + $this->pos += 1; + $result["text"] .= '('; + } + else { $_433 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $matcher = 'match_'.'QuotedString'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_433 = FALSE; break; } + $res_430 = $result; + $pos_430 = $this->pos; + $_429 = NULL; + do { + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == ',') { + $this->pos += 1; + $result["text"] .= ','; + } + else { $_429 = FALSE; break; } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + $matcher = 'match_'.'CallArguments'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { $this->store( $result, $subres ); } + else { $_429 = FALSE; break; } + $_429 = TRUE; break; + } + while(0); + if( $_429 === FALSE) { + $result = $res_430; + $this->pos = $pos_430; + unset( $res_430 ); + unset( $pos_430 ); + } + if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } + if (substr($this->string,$this->pos,1) == ')') { + $this->pos += 1; + $result["text"] .= ')'; + } + else { $_433 = FALSE; break; } + $_433 = TRUE; break; + } + while(0); + if( $_433 === TRUE ) { return $this->finalise($result); } + if( $_433 === FALSE) { return FALSE; } } @@ -1334,29 +2506,26 @@ class SSTemplateParser extends Parser { } /* OldTTag: "<%" < OldTPart > "%>" */ - function match_OldTTag ($substack = array()) { - $result = $this->construct( "OldTTag" ); - $_231 = NULL; + protected $match_OldTTag_typestack = array('OldTTag'); + function match_OldTTag ($stack = array()) { + $matchrule = "OldTTag"; $result = $this->construct($matchrule, $matchrule, null); + $_440 = NULL; do { - $_224 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_224->expand("<%") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_231 = FALSE; break; } + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_440 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "OldTPart"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OldTPart(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'OldTPart'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_231 = FALSE; break; } + else { $_440 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_229 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_229->expand("%>") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_231 = FALSE; break; } - $_231 = TRUE; break; + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_440 = FALSE; break; } + $_440 = TRUE; break; } while(0); - if( $_231 === TRUE ) { - return $this->finalise( "OldTTag", $result ); - } - if( $_231 === FALSE) { return FALSE; } + if( $_440 === TRUE ) { return $this->finalise($result); } + if( $_440 === FALSE) { return FALSE; } } @@ -1366,56 +2535,52 @@ class SSTemplateParser extends Parser { } /* OldSprintfTag: "<%" < "sprintf" < "(" < OldTPart < "," < CallArguments > ")" > "%>" */ - function match_OldSprintfTag ($substack = array()) { - $result = $this->construct( "OldSprintfTag" ); - $_251 = NULL; + protected $match_OldSprintfTag_typestack = array('OldSprintfTag'); + function match_OldSprintfTag ($stack = array()) { + $matchrule = "OldSprintfTag"; $result = $this->construct($matchrule, $matchrule, null); + $_457 = NULL; do { - $_233 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_233->expand("<%") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_251 = FALSE; break; } + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_457 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_236 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_236->expand("sprintf") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_251 = FALSE; break; } + if (( $subres = $this->literal( 'sprintf' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_457 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - if (substr($this->string,$this->pos,1) == "(") { + if (substr($this->string,$this->pos,1) == '(') { $this->pos += 1; - $result["text"] .= "("; + $result["text"] .= '('; } - else { $_251 = FALSE; break; } + else { $_457 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "OldTPart"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OldTPart(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'OldTPart'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_251 = FALSE; break; } + else { $_457 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - if (substr($this->string,$this->pos,1) == ",") { + if (substr($this->string,$this->pos,1) == ',') { $this->pos += 1; - $result["text"] .= ","; + $result["text"] .= ','; } - else { $_251 = FALSE; break; } + else { $_457 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "CallArguments"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_CallArguments(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'CallArguments'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_251 = FALSE; break; } + else { $_457 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - if (substr($this->string,$this->pos,1) == ")") { + if (substr($this->string,$this->pos,1) == ')') { $this->pos += 1; - $result["text"] .= ")"; + $result["text"] .= ')'; } - else { $_251 = FALSE; break; } + else { $_457 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_249 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_249->expand("%>") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_251 = FALSE; break; } - $_251 = TRUE; break; + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_457 = FALSE; break; } + $_457 = TRUE; break; } while(0); - if( $_251 === TRUE ) { - return $this->finalise( "OldSprintfTag", $result ); - } - if( $_251 === FALSE) { return FALSE; } + if( $_457 === TRUE ) { return $this->finalise($result); } + if( $_457 === FALSE) { return FALSE; } } @@ -1433,35 +2598,34 @@ class SSTemplateParser extends Parser { } /* OldI18NTag: OldSprintfTag | OldTTag */ - function match_OldI18NTag ($substack = array()) { - $result = $this->construct( "OldI18NTag" ); - $_256 = NULL; + protected $match_OldI18NTag_typestack = array('OldI18NTag'); + function match_OldI18NTag ($stack = array()) { + $matchrule = "OldI18NTag"; $result = $this->construct($matchrule, $matchrule, null); + $_462 = NULL; do { - $res_253 = $result; - $pos_253 = $this->pos; - $key = "OldSprintfTag"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OldSprintfTag(array_merge($substack, array($result))) ) ); + $res_459 = $result; + $pos_459 = $this->pos; + $matcher = 'match_'.'OldSprintfTag'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_256 = TRUE; break; + $_462 = TRUE; break; } - $result = $res_253; - $this->pos = $pos_253; - $key = "OldTTag"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OldTTag(array_merge($substack, array($result))) ) ); + $result = $res_459; + $this->pos = $pos_459; + $matcher = 'match_'.'OldTTag'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_256 = TRUE; break; + $_462 = TRUE; break; } - $result = $res_253; - $this->pos = $pos_253; - $_256 = FALSE; break; + $result = $res_459; + $this->pos = $pos_459; + $_462 = FALSE; break; } while(0); - if( $_256 === TRUE ) { - return $this->finalise( "OldI18NTag", $result ); - } - if( $_256 === FALSE) { return FALSE; } + if( $_462 === TRUE ) { return $this->finalise($result); } + if( $_462 === FALSE) { return FALSE; } } @@ -1471,251 +2635,283 @@ class SSTemplateParser extends Parser { } /* BlockArguments: :Argument ( < "," < :Argument)* */ - function match_BlockArguments ($substack = array()) { - $result = $this->construct( "BlockArguments" ); - $_265 = NULL; + protected $match_BlockArguments_typestack = array('BlockArguments'); + function match_BlockArguments ($stack = array()) { + $matchrule = "BlockArguments"; $result = $this->construct($matchrule, $matchrule, null); + $_471 = NULL; do { - $key = "Argument"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Argument'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Argument" ); } - else { $_265 = FALSE; break; } + else { $_471 = FALSE; break; } while (true) { - $res_264 = $result; - $pos_264 = $this->pos; - $_263 = NULL; + $res_470 = $result; + $pos_470 = $this->pos; + $_469 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - if (substr($this->string,$this->pos,1) == ",") { + if (substr($this->string,$this->pos,1) == ',') { $this->pos += 1; - $result["text"] .= ","; + $result["text"] .= ','; } - else { $_263 = FALSE; break; } + else { $_469 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $key = "Argument"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Argument(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Argument'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Argument" ); } - else { $_263 = FALSE; break; } - $_263 = TRUE; break; + else { $_469 = FALSE; break; } + $_469 = TRUE; break; } while(0); - if( $_263 === FALSE) { - $result = $res_264; - $this->pos = $pos_264; - unset( $res_264 ); - unset( $pos_264 ); + if( $_469 === FALSE) { + $result = $res_470; + $this->pos = $pos_470; + unset( $res_470 ); + unset( $pos_470 ); break; } } - $_265 = TRUE; break; + $_471 = TRUE; break; } while(0); - if( $_265 === TRUE ) { - return $this->finalise( "BlockArguments", $result ); - } - if( $_265 === FALSE) { return FALSE; } + if( $_471 === TRUE ) { return $this->finalise($result); } + if( $_471 === FALSE) { return FALSE; } } - /* NotBlockTag: "end_" | (("if" | "else_if" | "else" | "require") ] ) */ - function match_NotBlockTag ($substack = array()) { - $result = $this->construct( "NotBlockTag" ); - $_292 = NULL; + /* NotBlockTag: "end_" | (("if" | "else_if" | "else" | "require" | "cached" | "uncached" | "cacheblock") ] ) */ + protected $match_NotBlockTag_typestack = array('NotBlockTag'); + function match_NotBlockTag ($stack = array()) { + $matchrule = "NotBlockTag"; $result = $this->construct($matchrule, $matchrule, null); + $_505 = NULL; do { - $res_267 = $result; - $pos_267 = $this->pos; - $_268 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_268->expand("end_") ) ) !== FALSE) { + $res_473 = $result; + $pos_473 = $this->pos; + if (( $subres = $this->literal( 'end_' ) ) !== FALSE) { $result["text"] .= $subres; - $_292 = TRUE; break; + $_505 = TRUE; break; } - $result = $res_267; - $this->pos = $pos_267; - $_290 = NULL; + $result = $res_473; + $this->pos = $pos_473; + $_503 = NULL; do { - $_287 = NULL; + $_500 = NULL; do { - $_285 = NULL; + $_498 = NULL; do { - $res_270 = $result; - $pos_270 = $this->pos; - $_271 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_271->expand("if") ) ) !== FALSE) { + $res_475 = $result; + $pos_475 = $this->pos; + if (( $subres = $this->literal( 'if' ) ) !== FALSE) { $result["text"] .= $subres; - $_285 = TRUE; break; + $_498 = TRUE; break; } - $result = $res_270; - $this->pos = $pos_270; - $_283 = NULL; + $result = $res_475; + $this->pos = $pos_475; + $_496 = NULL; do { - $res_273 = $result; - $pos_273 = $this->pos; - $_274 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_274->expand("else_if") ) ) !== FALSE) { + $res_477 = $result; + $pos_477 = $this->pos; + if (( $subres = $this->literal( 'else_if' ) ) !== FALSE) { $result["text"] .= $subres; - $_283 = TRUE; break; + $_496 = TRUE; break; } - $result = $res_273; - $this->pos = $pos_273; - $_281 = NULL; + $result = $res_477; + $this->pos = $pos_477; + $_494 = NULL; do { - $res_276 = $result; - $pos_276 = $this->pos; - $_277 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_277->expand("else") ) ) !== FALSE) { + $res_479 = $result; + $pos_479 = $this->pos; + if (( $subres = $this->literal( 'else' ) ) !== FALSE) { $result["text"] .= $subres; - $_281 = TRUE; break; + $_494 = TRUE; break; } - $result = $res_276; - $this->pos = $pos_276; - $_279 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_279->expand("require") ) ) !== FALSE) { - $result["text"] .= $subres; - $_281 = TRUE; break; + $result = $res_479; + $this->pos = $pos_479; + $_492 = NULL; + do { + $res_481 = $result; + $pos_481 = $this->pos; + if (( $subres = $this->literal( 'require' ) ) !== FALSE) { + $result["text"] .= $subres; + $_492 = TRUE; break; + } + $result = $res_481; + $this->pos = $pos_481; + $_490 = NULL; + do { + $res_483 = $result; + $pos_483 = $this->pos; + if (( $subres = $this->literal( 'cached' ) ) !== FALSE) { + $result["text"] .= $subres; + $_490 = TRUE; break; + } + $result = $res_483; + $this->pos = $pos_483; + $_488 = NULL; + do { + $res_485 = $result; + $pos_485 = $this->pos; + if (( $subres = $this->literal( 'uncached' ) ) !== FALSE) { + $result["text"] .= $subres; + $_488 = TRUE; break; + } + $result = $res_485; + $this->pos = $pos_485; + if (( $subres = $this->literal( 'cacheblock' ) ) !== FALSE) { + $result["text"] .= $subres; + $_488 = TRUE; break; + } + $result = $res_485; + $this->pos = $pos_485; + $_488 = FALSE; break; + } + while(0); + if( $_488 === TRUE ) { $_490 = TRUE; break; } + $result = $res_483; + $this->pos = $pos_483; + $_490 = FALSE; break; + } + while(0); + if( $_490 === TRUE ) { $_492 = TRUE; break; } + $result = $res_481; + $this->pos = $pos_481; + $_492 = FALSE; break; } - $result = $res_276; - $this->pos = $pos_276; - $_281 = FALSE; break; + while(0); + if( $_492 === TRUE ) { $_494 = TRUE; break; } + $result = $res_479; + $this->pos = $pos_479; + $_494 = FALSE; break; } while(0); - if( $_281 === TRUE ) { $_283 = TRUE; break; } - $result = $res_273; - $this->pos = $pos_273; - $_283 = FALSE; break; + if( $_494 === TRUE ) { $_496 = TRUE; break; } + $result = $res_477; + $this->pos = $pos_477; + $_496 = FALSE; break; } while(0); - if( $_283 === TRUE ) { $_285 = TRUE; break; } - $result = $res_270; - $this->pos = $pos_270; - $_285 = FALSE; break; + if( $_496 === TRUE ) { $_498 = TRUE; break; } + $result = $res_475; + $this->pos = $pos_475; + $_498 = FALSE; break; } while(0); - if( $_285 === FALSE) { $_287 = FALSE; break; } - $_287 = TRUE; break; + if( $_498 === FALSE) { $_500 = FALSE; break; } + $_500 = TRUE; break; } while(0); - if( $_287 === FALSE) { $_290 = FALSE; break; } + if( $_500 === FALSE) { $_503 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_290 = FALSE; break; } - $_290 = TRUE; break; + else { $_503 = FALSE; break; } + $_503 = TRUE; break; } while(0); - if( $_290 === TRUE ) { $_292 = TRUE; break; } - $result = $res_267; - $this->pos = $pos_267; - $_292 = FALSE; break; + if( $_503 === TRUE ) { $_505 = TRUE; break; } + $result = $res_473; + $this->pos = $pos_473; + $_505 = FALSE; break; } while(0); - if( $_292 === TRUE ) { - return $this->finalise( "NotBlockTag", $result ); - } - if( $_292 === FALSE) { return FALSE; } + if( $_505 === TRUE ) { return $this->finalise($result); } + if( $_505 === FALSE) { return FALSE; } } - /* ClosedBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > Zap:'%>' :Template? '<%' < 'end_' '$BlockName' > '%>' */ - function match_ClosedBlock ($substack = array()) { - $result = $this->construct( "ClosedBlock" ); - $_319 = NULL; + /* ClosedBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > Zap:'%>' Template:$TemplateMatcher? '<%' < 'end_' '$BlockName' > '%>' */ + protected $match_ClosedBlock_typestack = array('ClosedBlock'); + function match_ClosedBlock ($stack = array()) { + $matchrule = "ClosedBlock"; $result = $this->construct($matchrule, $matchrule, null); + $_525 = NULL; do { - $_294 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_294->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_319 = FALSE; break; } + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_525 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_297 = $result; - $pos_297 = $this->pos; - $key = "NotBlockTag"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); + $res_509 = $result; + $pos_509 = $this->pos; + $matcher = 'match_'.'NotBlockTag'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $result = $res_297; - $this->pos = $pos_297; - $_319 = FALSE; break; + $result = $res_509; + $this->pos = $pos_509; + $_525 = FALSE; break; } else { - $result = $res_297; - $this->pos = $pos_297; + $result = $res_509; + $this->pos = $pos_509; } - $key = "Word"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Word'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockName" ); } - else { $_319 = FALSE; break; } - $res_303 = $result; - $pos_303 = $this->pos; - $_302 = NULL; + else { $_525 = FALSE; break; } + $res_515 = $result; + $pos_515 = $this->pos; + $_514 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_302 = FALSE; break; } - $key = "BlockArguments"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); + else { $_514 = FALSE; break; } + $matcher = 'match_'.'BlockArguments'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockArguments" ); } - else { $_302 = FALSE; break; } + else { $_514 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_302 = FALSE; break; } - $_302 = TRUE; break; + else { $_514 = FALSE; break; } + $_514 = TRUE; break; } while(0); - if( $_302 === FALSE) { - $result = $res_303; - $this->pos = $pos_303; - unset( $res_303 ); - unset( $pos_303 ); + if( $_514 === FALSE) { + $result = $res_515; + $this->pos = $pos_515; + unset( $res_515 ); + unset( $pos_515 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $substack[] = $result; - $result = $this->construct( "Zap" ); - $_305 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_305->expand('%>') ) ) !== FALSE) { + $stack[] = $result; $result = $this->construct( $matchrule, "Zap" ); + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; - $subres = $result ; - $result = array_pop( $substack ) ; + $subres = $result; $result = array_pop($stack); $this->store( $result, $subres, 'Zap' ); } else { - $result = array_pop( $substack ) ; - $_319 = FALSE; break; + $result = array_pop($stack); + $_525 = FALSE; break; } - $res_308 = $result; - $pos_308 = $this->pos; - $key = "Template"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Template(array_merge($substack, array($result))) ) ); + $res_518 = $result; + $pos_518 = $this->pos; + $matcher = 'match_'.$this->expression($result, $stack, 'TemplateMatcher'); $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Template" ); } else { - $result = $res_308; - $this->pos = $pos_308; - unset( $res_308 ); - unset( $pos_308 ); + $result = $res_518; + $this->pos = $pos_518; + unset( $res_518 ); + unset( $pos_518 ); } - $_309 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_309->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_319 = FALSE; break; } + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_525 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_312 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_312->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_319 = FALSE; break; } - $_314 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_314->expand('$BlockName') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_319 = FALSE; break; } + if (( $subres = $this->literal( 'end_' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_525 = FALSE; break; } + if (( $subres = $this->literal( ''.$this->expression($result, $stack, 'BlockName').'' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_525 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_317 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_317->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_319 = FALSE; break; } - $_319 = TRUE; break; + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_525 = FALSE; break; } + $_525 = TRUE; break; } while(0); - if( $_319 === TRUE ) { - return $this->finalise( "ClosedBlock", $result ); - } - if( $_319 === FALSE) { return FALSE; } + if( $_525 === TRUE ) { return $this->finalise($result); } + if( $_525 === FALSE) { return FALSE; } } @@ -1809,68 +3005,65 @@ class SSTemplateParser extends Parser { } /* OpenBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > '%>' */ - function match_OpenBlock ($substack = array()) { - $result = $this->construct( "OpenBlock" ); - $_334 = NULL; + protected $match_OpenBlock_typestack = array('OpenBlock'); + function match_OpenBlock ($stack = array()) { + $matchrule = "OpenBlock"; $result = $this->construct($matchrule, $matchrule, null); + $_538 = NULL; do { - $_321 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_321->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_334 = FALSE; break; } + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_538 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_324 = $result; - $pos_324 = $this->pos; - $key = "NotBlockTag"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); + $res_529 = $result; + $pos_529 = $this->pos; + $matcher = 'match_'.'NotBlockTag'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $result = $res_324; - $this->pos = $pos_324; - $_334 = FALSE; break; + $result = $res_529; + $this->pos = $pos_529; + $_538 = FALSE; break; } else { - $result = $res_324; - $this->pos = $pos_324; + $result = $res_529; + $this->pos = $pos_529; } - $key = "Word"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Word'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockName" ); } - else { $_334 = FALSE; break; } - $res_330 = $result; - $pos_330 = $this->pos; - $_329 = NULL; + else { $_538 = FALSE; break; } + $res_535 = $result; + $pos_535 = $this->pos; + $_534 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_329 = FALSE; break; } - $key = "BlockArguments"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); + else { $_534 = FALSE; break; } + $matcher = 'match_'.'BlockArguments'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockArguments" ); } - else { $_329 = FALSE; break; } + else { $_534 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_329 = FALSE; break; } - $_329 = TRUE; break; + else { $_534 = FALSE; break; } + $_534 = TRUE; break; } while(0); - if( $_329 === FALSE) { - $result = $res_330; - $this->pos = $pos_330; - unset( $res_330 ); - unset( $pos_330 ); + if( $_534 === FALSE) { + $result = $res_535; + $this->pos = $pos_535; + unset( $res_535 ); + unset( $pos_535 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_332 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_332->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_334 = FALSE; break; } - $_334 = TRUE; break; + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_538 = FALSE; break; } + $_538 = TRUE; break; } while(0); - if( $_334 === TRUE ) { - return $this->finalise( "OpenBlock", $result ); - } - if( $_334 === FALSE) { return FALSE; } + if( $_538 === TRUE ) { return $this->finalise($result); } + if( $_538 === FALSE) { return FALSE; } } @@ -1955,33 +3148,31 @@ class SSTemplateParser extends Parser { return '$val .= $_SERVER[SCRIPT_URL];'; } - /* MismatchedEndBlock: '<%' < 'end_' Word > '%>' */ - function match_MismatchedEndBlock ($substack = array()) { - $result = $this->construct( "MismatchedEndBlock" ); - $_345 = NULL; + /* MismatchedEndBlock: '<%' < 'end_' :Word > '%>' */ + protected $match_MismatchedEndBlock_typestack = array('MismatchedEndBlock'); + function match_MismatchedEndBlock ($stack = array()) { + $matchrule = "MismatchedEndBlock"; $result = $this->construct($matchrule, $matchrule, null); + $_546 = NULL; do { - $_336 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_336->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_345 = FALSE; break; } + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_546 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_339 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_339->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_345 = FALSE; break; } - $key = "Word"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { $this->store( $result, $subres ); } - else { $_345 = FALSE; break; } + if (( $subres = $this->literal( 'end_' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_546 = FALSE; break; } + $matcher = 'match_'.'Word'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres, "Word" ); + } + else { $_546 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_343 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_343->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_345 = FALSE; break; } - $_345 = TRUE; break; + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_546 = FALSE; break; } + $_546 = TRUE; break; } while(0); - if( $_345 === TRUE ) { - return $this->finalise( "MismatchedEndBlock", $result ); - } - if( $_345 === FALSE) { return FALSE; } + if( $_546 === TRUE ) { return $this->finalise($result); } + if( $_546 === FALSE) { return FALSE; } } @@ -1992,84 +3183,81 @@ class SSTemplateParser extends Parser { } /* MalformedOpenTag: '<%' < !NotBlockTag Tag:Word !( ( [ :BlockArguments ] )? > '%>' ) */ - function match_MalformedOpenTag ($substack = array()) { - $result = $this->construct( "MalformedOpenTag" ); - $_362 = NULL; + protected $match_MalformedOpenTag_typestack = array('MalformedOpenTag'); + function match_MalformedOpenTag ($stack = array()) { + $matchrule = "MalformedOpenTag"; $result = $this->construct($matchrule, $matchrule, null); + $_561 = NULL; do { - $_347 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_347->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_362 = FALSE; break; } + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_561 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $res_350 = $result; - $pos_350 = $this->pos; - $key = "NotBlockTag"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_NotBlockTag(array_merge($substack, array($result))) ) ); + $res_550 = $result; + $pos_550 = $this->pos; + $matcher = 'match_'.'NotBlockTag'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $result = $res_350; - $this->pos = $pos_350; - $_362 = FALSE; break; + $result = $res_550; + $this->pos = $pos_550; + $_561 = FALSE; break; } else { - $result = $res_350; - $this->pos = $pos_350; + $result = $res_550; + $this->pos = $pos_550; } - $key = "Word"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); + $matcher = 'match_'.'Word'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Tag" ); } - else { $_362 = FALSE; break; } - $res_361 = $result; - $pos_361 = $this->pos; - $_360 = NULL; + else { $_561 = FALSE; break; } + $res_560 = $result; + $pos_560 = $this->pos; + $_559 = NULL; do { - $res_356 = $result; - $pos_356 = $this->pos; - $_355 = NULL; + $res_556 = $result; + $pos_556 = $this->pos; + $_555 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_355 = FALSE; break; } - $key = "BlockArguments"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_BlockArguments(array_merge($substack, array($result))) ) ); + else { $_555 = FALSE; break; } + $matcher = 'match_'.'BlockArguments'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "BlockArguments" ); } - else { $_355 = FALSE; break; } + else { $_555 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_355 = FALSE; break; } - $_355 = TRUE; break; + else { $_555 = FALSE; break; } + $_555 = TRUE; break; } while(0); - if( $_355 === FALSE) { - $result = $res_356; - $this->pos = $pos_356; - unset( $res_356 ); - unset( $pos_356 ); + if( $_555 === FALSE) { + $result = $res_556; + $this->pos = $pos_556; + unset( $res_556 ); + unset( $pos_556 ); } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_358 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_358->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_360 = FALSE; break; } - $_360 = TRUE; break; + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_559 = FALSE; break; } + $_559 = TRUE; break; } while(0); - if( $_360 === TRUE ) { - $result = $res_361; - $this->pos = $pos_361; - $_362 = FALSE; break; + if( $_559 === TRUE ) { + $result = $res_560; + $this->pos = $pos_560; + $_561 = FALSE; break; } - if( $_360 === FALSE) { - $result = $res_361; - $this->pos = $pos_361; + if( $_559 === FALSE) { + $result = $res_560; + $this->pos = $pos_560; } - $_362 = TRUE; break; + $_561 = TRUE; break; } while(0); - if( $_362 === TRUE ) { - return $this->finalise( "MalformedOpenTag", $result ); - } - if( $_362 === FALSE) { return FALSE; } + if( $_561 === TRUE ) { return $this->finalise($result); } + if( $_561 === FALSE) { return FALSE; } } @@ -2080,66 +3268,60 @@ class SSTemplateParser extends Parser { } /* MalformedCloseTag: '<%' < Tag:('end_' :Word ) !( > '%>' ) */ - function match_MalformedCloseTag ($substack = array()) { - $result = $this->construct( "MalformedCloseTag" ); - $_378 = NULL; + protected $match_MalformedCloseTag_typestack = array('MalformedCloseTag'); + function match_MalformedCloseTag ($stack = array()) { + $matchrule = "MalformedCloseTag"; $result = $this->construct($matchrule, $matchrule, null); + $_573 = NULL; do { - $_364 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_364->expand('<%') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_378 = FALSE; break; } + if (( $subres = $this->literal( '<%' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_573 = FALSE; break; } if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $substack[] = $result; - $result = $this->construct( "Tag" ); - $_370 = NULL; + $stack[] = $result; $result = $this->construct( $matchrule, "Tag" ); + $_567 = NULL; do { - $_367 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_367->expand('end_') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_370 = FALSE; break; } - $key = "Word"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Word(array_merge($substack, array($result))) ) ); + if (( $subres = $this->literal( 'end_' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_567 = FALSE; break; } + $matcher = 'match_'.'Word'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres, "Word" ); } - else { $_370 = FALSE; break; } - $_370 = TRUE; break; + else { $_567 = FALSE; break; } + $_567 = TRUE; break; } while(0); - if( $_370 === TRUE ) { - $subres = $result ; - $result = array_pop( $substack ) ; + if( $_567 === TRUE ) { + $subres = $result; $result = array_pop($stack); $this->store( $result, $subres, 'Tag' ); } - if( $_370 === FALSE) { - $result = array_pop( $substack ) ; - $_378 = FALSE; break; + if( $_567 === FALSE) { + $result = array_pop($stack); + $_573 = FALSE; break; } - $res_377 = $result; - $pos_377 = $this->pos; - $_376 = NULL; + $res_572 = $result; + $pos_572 = $this->pos; + $_571 = NULL; do { if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; } - $_374 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_374->expand('%>') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_376 = FALSE; break; } - $_376 = TRUE; break; + if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_571 = FALSE; break; } + $_571 = TRUE; break; } while(0); - if( $_376 === TRUE ) { - $result = $res_377; - $this->pos = $pos_377; - $_378 = FALSE; break; + if( $_571 === TRUE ) { + $result = $res_572; + $this->pos = $pos_572; + $_573 = FALSE; break; } - if( $_376 === FALSE) { - $result = $res_377; - $this->pos = $pos_377; + if( $_571 === FALSE) { + $result = $res_572; + $this->pos = $pos_572; } - $_378 = TRUE; break; + $_573 = TRUE; break; } while(0); - if( $_378 === TRUE ) { - return $this->finalise( "MalformedCloseTag", $result ); - } - if( $_378 === FALSE) { return FALSE; } + if( $_573 === TRUE ) { return $this->finalise($result); } + if( $_573 === FALSE) { return FALSE; } } @@ -2150,94 +3332,88 @@ class SSTemplateParser extends Parser { } /* MalformedBlock: MalformedOpenTag | MalformedCloseTag */ - function match_MalformedBlock ($substack = array()) { - $result = $this->construct( "MalformedBlock" ); - $_383 = NULL; + protected $match_MalformedBlock_typestack = array('MalformedBlock'); + function match_MalformedBlock ($stack = array()) { + $matchrule = "MalformedBlock"; $result = $this->construct($matchrule, $matchrule, null); + $_578 = NULL; do { - $res_380 = $result; - $pos_380 = $this->pos; - $key = "MalformedOpenTag"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedOpenTag(array_merge($substack, array($result))) ) ); + $res_575 = $result; + $pos_575 = $this->pos; + $matcher = 'match_'.'MalformedOpenTag'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_383 = TRUE; break; + $_578 = TRUE; break; } - $result = $res_380; - $this->pos = $pos_380; - $key = "MalformedCloseTag"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedCloseTag(array_merge($substack, array($result))) ) ); + $result = $res_575; + $this->pos = $pos_575; + $matcher = 'match_'.'MalformedCloseTag'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_383 = TRUE; break; + $_578 = TRUE; break; } - $result = $res_380; - $this->pos = $pos_380; - $_383 = FALSE; break; + $result = $res_575; + $this->pos = $pos_575; + $_578 = FALSE; break; } while(0); - if( $_383 === TRUE ) { - return $this->finalise( "MalformedBlock", $result ); - } - if( $_383 === FALSE) { return FALSE; } + if( $_578 === TRUE ) { return $this->finalise($result); } + if( $_578 === FALSE) { return FALSE; } } /* Comment: "<%--" (!"--%>" /./)+ "--%>" */ - function match_Comment ($substack = array()) { - $result = $this->construct( "Comment" ); - $_395 = NULL; + protected $match_Comment_typestack = array('Comment'); + function match_Comment ($stack = array()) { + $matchrule = "Comment"; $result = $this->construct($matchrule, $matchrule, null); + $_586 = NULL; do { - $_385 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_385->expand("<%--") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_395 = FALSE; break; } + if (( $subres = $this->literal( '<%--' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_586 = FALSE; break; } $count = 0; while (true) { - $res_392 = $result; - $pos_392 = $this->pos; - $_391 = NULL; + $res_584 = $result; + $pos_584 = $this->pos; + $_583 = NULL; do { - $res_388 = $result; - $pos_388 = $this->pos; - $_387 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_387->expand("--%>") ) ) !== FALSE) { + $res_581 = $result; + $pos_581 = $this->pos; + if (( $subres = $this->literal( '--%>' ) ) !== FALSE) { $result["text"] .= $subres; - $result = $res_388; - $this->pos = $pos_388; - $_391 = FALSE; break; + $result = $res_581; + $this->pos = $pos_581; + $_583 = FALSE; break; } else { - $result = $res_388; - $this->pos = $pos_388; + $result = $res_581; + $this->pos = $pos_581; } - $_389 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_389->expand('/./') ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_391 = FALSE; break; } - $_391 = TRUE; break; + if (( $subres = $this->rx( '/./' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_583 = FALSE; break; } + $_583 = TRUE; break; } while(0); - if( $_391 === FALSE) { - $result = $res_392; - $this->pos = $pos_392; - unset( $res_392 ); - unset( $pos_392 ); + if( $_583 === FALSE) { + $result = $res_584; + $this->pos = $pos_584; + unset( $res_584 ); + unset( $pos_584 ); break; } $count += 1; } if ($count > 0) { } - else { $_395 = FALSE; break; } - $_393 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->literal( $_393->expand("--%>") ) ) !== FALSE) { $result["text"] .= $subres; } - else { $_395 = FALSE; break; } - $_395 = TRUE; break; + else { $_586 = FALSE; break; } + if (( $subres = $this->literal( '--%>' ) ) !== FALSE) { $result["text"] .= $subres; } + else { $_586 = FALSE; break; } + $_586 = TRUE; break; } while(0); - if( $_395 === TRUE ) { - return $this->finalise( "Comment", $result ); - } - if( $_395 === FALSE) { return FALSE; } + if( $_586 === TRUE ) { return $this->finalise($result); } + if( $_586 === FALSE) { return FALSE; } } @@ -2245,433 +3421,234 @@ class SSTemplateParser extends Parser { function Comment__construct(&$res) { $res['php'] = ''; } - - /* Text: / -( -(\\.) | # Any escaped character -([^<${]) | # Any character that isn't <, $ or { -(<[^%]) | # < if not followed by % -($[^A-Za-z_]) | # $ if not followed by A-Z, a-z or _ -({[^$]) | # { if not followed by $ -({$[^A-Za-z_]) # {$ if not followed A-Z, a-z or _ -)+ -/ */ - function match_Text ($substack = array()) { - $result = array("name"=>"Text", "text"=>""); - $_397 = new ParserExpression( $this, $substack, $result ); - if (( $subres = $this->rx( $_397->expand('/ -( -(\\\\.) | # Any escaped character -([^<${]) | # Any character that isn\'t <, $ or { -(<[^%]) | # < if not followed by % -($[^A-Za-z_]) | # $ if not followed by A-Z, a-z or _ -({[^$]) | # { if not followed by $ -({$[^A-Za-z_]) # {$ if not followed A-Z, a-z or _ -)+ -/') ) ) !== FALSE) { - $result["text"] .= $subres; - return $result; - } - else { return FALSE; } - } - - - /* Template: (Comment | If | Require | OldI18NTag | ClosedBlock | OpenBlock | MalformedBlock | Injection | Text)+ */ - function match_Template ($substack = array()) { - $result = $this->construct( "Template" ); - $count = 0; - while (true) { - $res_433 = $result; - $pos_433 = $this->pos; - $_432 = NULL; - do { - $_430 = NULL; - do { - $res_399 = $result; - $pos_399 = $this->pos; - $key = "Comment"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comment(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_430 = TRUE; break; - } - $result = $res_399; - $this->pos = $pos_399; - $_428 = NULL; - do { - $res_401 = $result; - $pos_401 = $this->pos; - $key = "If"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_If(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_428 = TRUE; break; - } - $result = $res_401; - $this->pos = $pos_401; - $_426 = NULL; - do { - $res_403 = $result; - $pos_403 = $this->pos; - $key = "Require"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Require(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_426 = TRUE; break; - } - $result = $res_403; - $this->pos = $pos_403; - $_424 = NULL; - do { - $res_405 = $result; - $pos_405 = $this->pos; - $key = "OldI18NTag"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OldI18NTag(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_424 = TRUE; break; - } - $result = $res_405; - $this->pos = $pos_405; - $_422 = NULL; - do { - $res_407 = $result; - $pos_407 = $this->pos; - $key = "ClosedBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_422 = TRUE; break; - } - $result = $res_407; - $this->pos = $pos_407; - $_420 = NULL; - do { - $res_409 = $result; - $pos_409 = $this->pos; - $key = "OpenBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_420 = TRUE; break; - } - $result = $res_409; - $this->pos = $pos_409; - $_418 = NULL; - do { - $res_411 = $result; - $pos_411 = $this->pos; - $key = "MalformedBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_418 = TRUE; break; - } - $result = $res_411; - $this->pos = $pos_411; - $_416 = NULL; - do { - $res_413 = $result; - $pos_413 = $this->pos; - $key = "Injection"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_416 = TRUE; break; - } - $result = $res_413; - $this->pos = $pos_413; - $key = "Text"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_416 = TRUE; break; - } - $result = $res_413; - $this->pos = $pos_413; - $_416 = FALSE; break; - } - while(0); - if( $_416 === TRUE ) { $_418 = TRUE; break; } - $result = $res_411; - $this->pos = $pos_411; - $_418 = FALSE; break; - } - while(0); - if( $_418 === TRUE ) { $_420 = TRUE; break; } - $result = $res_409; - $this->pos = $pos_409; - $_420 = FALSE; break; - } - while(0); - if( $_420 === TRUE ) { $_422 = TRUE; break; } - $result = $res_407; - $this->pos = $pos_407; - $_422 = FALSE; break; - } - while(0); - if( $_422 === TRUE ) { $_424 = TRUE; break; } - $result = $res_405; - $this->pos = $pos_405; - $_424 = FALSE; break; - } - while(0); - if( $_424 === TRUE ) { $_426 = TRUE; break; } - $result = $res_403; - $this->pos = $pos_403; - $_426 = FALSE; break; - } - while(0); - if( $_426 === TRUE ) { $_428 = TRUE; break; } - $result = $res_401; - $this->pos = $pos_401; - $_428 = FALSE; break; - } - while(0); - if( $_428 === TRUE ) { $_430 = TRUE; break; } - $result = $res_399; - $this->pos = $pos_399; - $_430 = FALSE; break; - } - while(0); - if( $_430 === FALSE) { $_432 = FALSE; break; } - $_432 = TRUE; break; - } - while(0); - if( $_432 === FALSE) { - $result = $res_433; - $this->pos = $pos_433; - unset( $res_433 ); - unset( $pos_433 ); - break; - } - $count += 1; - } - if ($count > 0) { - return $this->finalise( "Template", $result ); - } - else { return FALSE; } - } - - - - function Template__construct(&$res) { - $res['php'] = ''; - } - - function Template_Text(&$res, $sub) { - $text = $sub['text']; - $text = preg_replace( - '/href\s*\=\s*\"\#/', - 'href="#', - $text - ); - - // TODO: using heredocs means any left over $ symbols will trigger PHP lookups, as will any escapes - // Will it break backwards compatibility to use ' quoted strings, and escape just the ' characters? - $res['php'] .= - '$val .= <<construct( "TopTemplate" ); + /* TopTemplate: (Comment | If | Require | CacheBlock | UncachedBlock | OldI18NTag | ClosedBlock | OpenBlock | MalformedBlock | MismatchedEndBlock | Injection | Text)+ */ + protected $match_TopTemplate_typestack = array('TopTemplate','Template'); + function match_TopTemplate ($stack = array()) { + $matchrule = "TopTemplate"; $result = $this->construct($matchrule, $matchrule, array('TemplateMatcher' => 'Template')); $count = 0; while (true) { - $res_472 = $result; - $pos_472 = $this->pos; - $_471 = NULL; + $res_634 = $result; + $pos_634 = $this->pos; + $_633 = NULL; do { - $_469 = NULL; + $_631 = NULL; do { - $res_434 = $result; - $pos_434 = $this->pos; - $key = "Comment"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Comment(array_merge($substack, array($result))) ) ); + $res_588 = $result; + $pos_588 = $this->pos; + $matcher = 'match_'.'Comment'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_469 = TRUE; break; + $_631 = TRUE; break; } - $result = $res_434; - $this->pos = $pos_434; - $_467 = NULL; + $result = $res_588; + $this->pos = $pos_588; + $_629 = NULL; do { - $res_436 = $result; - $pos_436 = $this->pos; - $key = "If"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_If(array_merge($substack, array($result))) ) ); + $res_590 = $result; + $pos_590 = $this->pos; + $matcher = 'match_'.'If'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_467 = TRUE; break; + $_629 = TRUE; break; } - $result = $res_436; - $this->pos = $pos_436; - $_465 = NULL; + $result = $res_590; + $this->pos = $pos_590; + $_627 = NULL; do { - $res_438 = $result; - $pos_438 = $this->pos; - $key = "Require"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Require(array_merge($substack, array($result))) ) ); + $res_592 = $result; + $pos_592 = $this->pos; + $matcher = 'match_'.'Require'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_465 = TRUE; break; + $_627 = TRUE; break; } - $result = $res_438; - $this->pos = $pos_438; - $_463 = NULL; + $result = $res_592; + $this->pos = $pos_592; + $_625 = NULL; do { - $res_440 = $result; - $pos_440 = $this->pos; - $key = "OldI18NTag"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OldI18NTag(array_merge($substack, array($result))) ) ); + $res_594 = $result; + $pos_594 = $this->pos; + $matcher = 'match_'.'CacheBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_463 = TRUE; break; + $_625 = TRUE; break; } - $result = $res_440; - $this->pos = $pos_440; - $_461 = NULL; + $result = $res_594; + $this->pos = $pos_594; + $_623 = NULL; do { - $res_442 = $result; - $pos_442 = $this->pos; - $key = "ClosedBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_ClosedBlock(array_merge($substack, array($result))) ) ); + $res_596 = $result; + $pos_596 = $this->pos; + $matcher = 'match_'.'UncachedBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_461 = TRUE; break; + $_623 = TRUE; break; } - $result = $res_442; - $this->pos = $pos_442; - $_459 = NULL; + $result = $res_596; + $this->pos = $pos_596; + $_621 = NULL; do { - $res_444 = $result; - $pos_444 = $this->pos; - $key = "OpenBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_OpenBlock(array_merge($substack, array($result))) ) ); + $res_598 = $result; + $pos_598 = $this->pos; + $matcher = 'match_'.'OldI18NTag'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_459 = TRUE; break; + $_621 = TRUE; break; } - $result = $res_444; - $this->pos = $pos_444; - $_457 = NULL; + $result = $res_598; + $this->pos = $pos_598; + $_619 = NULL; do { - $res_446 = $result; - $pos_446 = $this->pos; - $key = "MalformedBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MalformedBlock(array_merge($substack, array($result))) ) ); + $res_600 = $result; + $pos_600 = $this->pos; + $matcher = 'match_'.'ClosedBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_457 = TRUE; break; + $_619 = TRUE; break; } - $result = $res_446; - $this->pos = $pos_446; - $_455 = NULL; + $result = $res_600; + $this->pos = $pos_600; + $_617 = NULL; do { - $res_448 = $result; - $pos_448 = $this->pos; - $key = "MismatchedEndBlock"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_MismatchedEndBlock(array_merge($substack, array($result))) ) ); + $res_602 = $result; + $pos_602 = $this->pos; + $matcher = 'match_'.'OpenBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_455 = TRUE; break; + $_617 = TRUE; break; } - $result = $res_448; - $this->pos = $pos_448; - $_453 = NULL; + $result = $res_602; + $this->pos = $pos_602; + $_615 = NULL; do { - $res_450 = $result; - $pos_450 = $this->pos; - $key = "Injection"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Injection(array_merge($substack, array($result))) ) ); + $res_604 = $result; + $pos_604 = $this->pos; + $matcher = 'match_'.'MalformedBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); if ($subres !== FALSE) { $this->store( $result, $subres ); - $_453 = TRUE; break; + $_615 = TRUE; break; } - $result = $res_450; - $this->pos = $pos_450; - $key = "Text"; $pos = $this->pos; - $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->match_Text(array_merge($substack, array($result))) ) ); - if ($subres !== FALSE) { - $this->store( $result, $subres ); - $_453 = TRUE; break; + $result = $res_604; + $this->pos = $pos_604; + $_613 = NULL; + do { + $res_606 = $result; + $pos_606 = $this->pos; + $matcher = 'match_'.'MismatchedEndBlock'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_613 = TRUE; break; + } + $result = $res_606; + $this->pos = $pos_606; + $_611 = NULL; + do { + $res_608 = $result; + $pos_608 = $this->pos; + $matcher = 'match_'.'Injection'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_611 = TRUE; break; + } + $result = $res_608; + $this->pos = $pos_608; + $matcher = 'match_'.'Text'; $key = $matcher; $pos = $this->pos; + $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) ); + if ($subres !== FALSE) { + $this->store( $result, $subres ); + $_611 = TRUE; break; + } + $result = $res_608; + $this->pos = $pos_608; + $_611 = FALSE; break; + } + while(0); + if( $_611 === TRUE ) { $_613 = TRUE; break; } + $result = $res_606; + $this->pos = $pos_606; + $_613 = FALSE; break; } - $result = $res_450; - $this->pos = $pos_450; - $_453 = FALSE; break; + while(0); + if( $_613 === TRUE ) { $_615 = TRUE; break; } + $result = $res_604; + $this->pos = $pos_604; + $_615 = FALSE; break; } while(0); - if( $_453 === TRUE ) { $_455 = TRUE; break; } - $result = $res_448; - $this->pos = $pos_448; - $_455 = FALSE; break; + if( $_615 === TRUE ) { $_617 = TRUE; break; } + $result = $res_602; + $this->pos = $pos_602; + $_617 = FALSE; break; } while(0); - if( $_455 === TRUE ) { $_457 = TRUE; break; } - $result = $res_446; - $this->pos = $pos_446; - $_457 = FALSE; break; + if( $_617 === TRUE ) { $_619 = TRUE; break; } + $result = $res_600; + $this->pos = $pos_600; + $_619 = FALSE; break; } while(0); - if( $_457 === TRUE ) { $_459 = TRUE; break; } - $result = $res_444; - $this->pos = $pos_444; - $_459 = FALSE; break; + if( $_619 === TRUE ) { $_621 = TRUE; break; } + $result = $res_598; + $this->pos = $pos_598; + $_621 = FALSE; break; } while(0); - if( $_459 === TRUE ) { $_461 = TRUE; break; } - $result = $res_442; - $this->pos = $pos_442; - $_461 = FALSE; break; + if( $_621 === TRUE ) { $_623 = TRUE; break; } + $result = $res_596; + $this->pos = $pos_596; + $_623 = FALSE; break; } while(0); - if( $_461 === TRUE ) { $_463 = TRUE; break; } - $result = $res_440; - $this->pos = $pos_440; - $_463 = FALSE; break; + if( $_623 === TRUE ) { $_625 = TRUE; break; } + $result = $res_594; + $this->pos = $pos_594; + $_625 = FALSE; break; } while(0); - if( $_463 === TRUE ) { $_465 = TRUE; break; } - $result = $res_438; - $this->pos = $pos_438; - $_465 = FALSE; break; + if( $_625 === TRUE ) { $_627 = TRUE; break; } + $result = $res_592; + $this->pos = $pos_592; + $_627 = FALSE; break; } while(0); - if( $_465 === TRUE ) { $_467 = TRUE; break; } - $result = $res_436; - $this->pos = $pos_436; - $_467 = FALSE; break; + if( $_627 === TRUE ) { $_629 = TRUE; break; } + $result = $res_590; + $this->pos = $pos_590; + $_629 = FALSE; break; } while(0); - if( $_467 === TRUE ) { $_469 = TRUE; break; } - $result = $res_434; - $this->pos = $pos_434; - $_469 = FALSE; break; + if( $_629 === TRUE ) { $_631 = TRUE; break; } + $result = $res_588; + $this->pos = $pos_588; + $_631 = FALSE; break; } while(0); - if( $_469 === FALSE) { $_471 = FALSE; break; } - $_471 = TRUE; break; + if( $_631 === FALSE) { $_633 = FALSE; break; } + $_633 = TRUE; break; } while(0); - if( $_471 === FALSE) { - $result = $res_472; - $this->pos = $pos_472; - unset( $res_472 ); - unset( $pos_472 ); + if( $_633 === FALSE) { + $result = $res_634; + $this->pos = $pos_634; + unset( $res_634 ); + unset( $pos_634 ); break; } $count += 1; } - if ($count > 0) { - return $this->finalise( "TopTemplate", $result ); - } + if ($count > 0) { return $this->finalise($result); } else { return FALSE; } } @@ -2685,13 +3662,59 @@ class SSTemplateParser extends Parser { $res['php'] = "Template_Text($res, $sub); } - function TopTemplate_STR(&$res, $sub) { return $this->Template_STR($res, $sub); } + /* Text: / + ( + (\\.) | # Any escaped character + ([^<${]) | # Any character that isn't <, $ or { + (<[^%]) | # < if not followed by % + ($[^A-Za-z_]) | # $ if not followed by A-Z, a-z or _ + ({[^$]) | # { if not followed by $ + ({$[^A-Za-z_]) # {$ if not followed A-Z, a-z or _ + )+ + / */ + protected $match_Text_typestack = array('Text'); + function match_Text ($stack = array()) { + $matchrule = "Text"; $result = $this->construct($matchrule, $matchrule, null); + if (( $subres = $this->rx( '/ + ( + (\\\\.) | # Any escaped character + ([^<${]) | # Any character that isn\'t <, $ or { + (<[^%]) | # < if not followed by % + ($[^A-Za-z_]) | # $ if not followed by A-Z, a-z or _ + ({[^$]) | # { if not followed by $ + ({$[^A-Za-z_]) # {$ if not followed A-Z, a-z or _ + )+ + /' ) ) !== FALSE) { + $result["text"] .= $subres; + return $this->finalise($result); + } + else { return FALSE; } + } + + + /** + * We convert text + */ + function Text__finalise(&$res) { + $text = $res['text']; + + $text = preg_replace( + '/href\s*\=\s*\"\#/', + 'href="#', + $text + ); + + // TODO: using heredocs means any left over $ symbols will trigger PHP lookups, as will any escapes + // Will it break backwards compatibility to use ' quoted strings, and escape just the ' characters? + + $res['php'] .= + '$val .= << '%>' :Template? - ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' :Template - ElsePart: '<%' < 'else' > '%>' :Template + IfPart: '<%' < 'if' [ :IfArgument > '%>' Template:$TemplateMatcher? + ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' Template:$TemplateMatcher + ElsePart: '<%' < 'else' > '%>' Template:$TemplateMatcher If: IfPart ElseIfPart* ElsePart? '<%' < 'end_if' > '%>' */ @@ -375,6 +386,120 @@ class SSTemplateParser extends Parser { $res['php'] = "Requirements::".$sub['Method']['text'].'('.$sub['CallArguments']['php'].');'; } + + /*!* + + # Cache block arguments don't support free strings + + CacheBlockArgument: + !( "if " | "unless " ) + ( + :DollarMarkedLookup | + :QuotedString | + :Lookup + ) + */ + function CacheBlockArgument_DollarMarkedLookup(&$res, $sub) { + $res['php'] = $sub['Lookup']['php']; + } + + function CacheBlockArgument_QuotedString(&$res, $sub) { + $res['php'] = "'" . str_replace("'", "\\'", $sub['String']['text']) . "'"; + } + + function CacheBlockArgument_Lookup(&$res, $sub) { + $res['php'] = $sub['php']; + } + + /*!* + + # Collects the arguments passed in to be part of the key of a cacheblock + + CacheBlockArguments: CacheBlockArgument ( < "," < CacheBlockArgument )* + + */ + function CacheBlockArguments_CacheBlockArgument(&$res, $sub) { + if (!empty($res['php'])) $res['php'] .= ".'_'."; + else $res['php'] = ''; + + $res['php'] .= str_replace('$$FINAL', 'XML_val', $sub['php']); + } + + /*!* + # CacheBlockTemplate is the same as Template, but doesn't include cache blocks (because they're handled seperately) + + CacheBlockTemplate extends Template (TemplateMatcher = CacheRestrictedTemplate); CacheBlock | UncachedBlock | => '' + */ + + /*!* + + UncachedBlock: + '<%' < "uncached" < CacheBlockArguments? ( < Conditional:("if"|"unless") > Condition:IfArgument )? > '%>' + Template:$TemplateMatcher? + '<%' < 'end_' ("uncached"|"cached"|"cacheblock") > '%>' + */ + function UncachedBlock_Template(&$res, $sub){ + $res['php'] = $sub['php']; + } + + /*!* + + # CacheRestrictedTemplate is the same as Template, but doesn't allow cache blocks + + CacheRestrictedTemplate extends Template + */ + function CacheRestrictedTemplate_CacheBlock(&$res, $sub) { + throw new SSTemplateParseException('You cant have cache blocks nested within with, loop or control blocks that are within cache blocks', $this); + } + + function CacheRestrictedTemplate_UncachedBlock(&$res, $sub) { + throw new SSTemplateParseException('You cant have uncache blocks nested within with, loop or control blocks that are within cache blocks', $this); + } + + /*!* + # The partial caching block + + CacheBlock: + '<%' < CacheTag:("cached"|"cacheblock") < (CacheBlockArguments)? ( < Conditional:("if"|"unless") > Condition:IfArgument )? > '%>' + (CacheBlock | UncachedBlock | CacheBlockTemplate)* + '<%' < 'end_' ("cached"|"uncached"|"cacheblock") > '%>' + + */ + function CacheBlock__construct(&$res){ + $res['subblocks'] = 0; + } + + function CacheBlock_CacheBlockArguments(&$res, $sub){ + $res['key'] = !empty($sub['php']) ? $sub['php'] : ''; + } + + function CacheBlock_Condition(&$res, $sub){ + $res['condition'] = ($res['Conditional']['text'] == 'if' ? '(' : '!(') . $sub['php'] . ') && '; + } + + function CacheBlock_CacheBlock(&$res, $sub){ + $res['php'] .= $sub['php']; + } + + function CacheBlock_UncachedBlock(&$res, $sub){ + $res['php'] .= $sub['php']; + } + + function CacheBlock_CacheBlockTemplate(&$res, $sub){ + // Get the block counter + $block = ++$res['subblocks']; + // Build the key for this block from the passed cache key, the block index, and the sha hash of the template itself + $key = "'" . sha1($sub['php']) . (isset($res['key']) && $res['key'] ? "_'.sha1(".$res['key'].")" : "'") . ".'_$block'"; + // Get any condition + $condition = isset($res['condition']) ? $res['condition'] : ''; + + $res['php'] .= 'if ('.$condition.'($partial = $cache->load('.$key.'))) $val .= $partial;' . PHP_EOL; + $res['php'] .= 'else { $oldval = $val; $val = "";' . PHP_EOL; + $res['php'] .= $sub['php'] . PHP_EOL; + $res['php'] .= $condition . ' $cache->save($val); $val = $oldval . $val;' . PHP_EOL; + $res['php'] .= '}'; + } + /*!* # Deprecated old-style i18n _t and sprintf(_t block tags. We support a slightly more flexible version than we used @@ -461,12 +586,12 @@ class SSTemplateParser extends Parser { # NotBlockTag matches against any word that might come after a "<%" that the generic open and closed block handlers # shouldn't attempt to match against, because they're handled by more explicit matchers - NotBlockTag: "end_" | (("if" | "else_if" | "else" | "require") ] ) + NotBlockTag: "end_" | (("if" | "else_if" | "else" | "require" | "cached" | "uncached" | "cacheblock") ] ) # Match against closed blocks - blocks with an opening and a closing tag that surround some internal portion of # template - ClosedBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > Zap:'%>' :Template? '<%' < 'end_' '$BlockName' > '%>' + ClosedBlock: '<%' < !NotBlockTag BlockName:Word ( [ :BlockArguments ] )? > Zap:'%>' Template:$TemplateMatcher? '<%' < 'end_' '$BlockName' > '%>' */ /** @@ -649,7 +774,7 @@ class SSTemplateParser extends Parser { # Because of parser limitations, this can only be used at the top nesting level of a template. Other mismatched # closing tags are detected as an invalid open tag - MismatchedEndBlock: '<%' < 'end_' Word > '%>' + MismatchedEndBlock: '<%' < 'end_' :Word > '%>' */ function MismatchedEndBlock__finalise(&$res) { $blockname = $res['Word']['text']; @@ -696,7 +821,22 @@ class SSTemplateParser extends Parser { function Comment__construct(&$res) { $res['php'] = ''; } + + /*!* + # TopTemplate is the same as Template, but should only be used at the top level (not nested), as it includes + # MismatchedEndBlock detection, which only works at the top level + + TopTemplate extends Template (TemplateMatcher = Template); MalformedBlock => MalformedBlock | MismatchedEndBlock + */ + + /** + * The TopTemplate also includes the opening stanza to start off the template + */ + function TopTemplate__construct(&$res) { + $res['php'] = "#', @@ -731,39 +867,13 @@ class SSTemplateParser extends Parser { // TODO: using heredocs means any left over $ symbols will trigger PHP lookups, as will any escapes // Will it break backwards compatibility to use ' quoted strings, and escape just the ' characters? - + $res['php'] .= '$val .= <<Template_Text($res, $sub); } - function TopTemplate_STR(&$res, $sub) { return $this->Template_STR($res, $sub); } - - + /****************** * Here ends the parser itself. Below are utility methods to use the parser */ diff --git a/tests/SSViewerCacheBlockTest.php b/tests/SSViewerCacheBlockTest.php index 5500ca584..c1d4fbf95 100644 --- a/tests/SSViewerCacheBlockTest.php +++ b/tests/SSViewerCacheBlockTest.php @@ -186,6 +186,11 @@ class SSViewerCacheBlockTest extends SapphireTest { $this->assertEquals($this->_runtemplate($template, array('Foo' => 2, 'Fooa' => 9, 'Foob' => 9, 'Bar' => 2, 'Bara' => 1)), ' 9 9 9 '); } + function testNoErrorMessageForControlWithinCached() { + $this->_reset(true); + $this->_runtemplate('<% cached %><% control Foo %>$Bar<% end_control %><% end_cached %>'); + } + /** * @expectedException Exception */ From 31c5bb24f7af15fd03369700972a14473d32fb6d Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Thu, 10 Mar 2011 17:37:46 +1300 Subject: [PATCH 14/15] MINOR: Remove now-obsolete old partial cache code --- core/SSViewer.php | 255 +--------------------------------------------- 1 file changed, 1 insertion(+), 254 deletions(-) diff --git a/core/SSViewer.php b/core/SSViewer.php index 0f40795ed..ae9f881f3 100755 --- a/core/SSViewer.php +++ b/core/SSViewer.php @@ -586,7 +586,7 @@ class SSViewer { } $scope = new SSViewer_DataPresenter($item, array('I18NNamespace' => basename($template))); - $val = ""; $valStack = array(); + $val = ""; include($cacheFile); @@ -702,256 +702,3 @@ class SSViewer_FromString extends SSViewer { return $val; } } - -/** - * Handle the parsing for cacheblock tags. - * - * Needs to be handled differently from the other tags, because cacheblock can take any number of arguments - * - * This shouldn't be used as an example of how to add functionality to SSViewer - the eventual plan is to re-write - * SSViewer using a proper parser (probably http://github.com/hafriedlander/php-peg), so that extra functionality - * can be added without relying on ad-hoc parsers like this. - * - * @package sapphire - * @subpackage view - */ -class SSViewer_PartialParser { - - static $tag = '/< % [ \t]+ (cached|cacheblock|uncached|end_cached|end_cacheblock|end_uncached) [ \t]+ ([^%]+ [ \t]+)? % >/xS'; - - static $argument_splitter = '/^\s* - # The argument itself - ( - (?P if | unless ) | # The if or unless keybreak - (?P (?P \w+) \s* # A property lookup or a function call - ( \( (?P [^\)]*) \) )? - ) | - (?P \' (\\\'|[^\'])+ \' ) | # A string surrounded by \' - (?P " (\\"|[^"])+ " ) # A string surrounded by " - ) - # Some seperator after the argument - ( - \s*(?P,)\s* | # A comma (maybe with whitespace before or after) - (?P\.) # A period (no whitespace before) - )? - /xS'; - - static function process($template, $content) { - $parser = new SSViewer_PartialParser($template, $content, 0); - $parser->parse(); - return $parser->generate(); - } - - function __construct($template, $content, $offset) { - $this->template = $template; - $this->content = $content; - $this->offset = $offset; - - $this->blocks = array(); - } - - function controlcheck($text) { - // NOP - hook for Cached_PartialParser - } - - function parse() { - $current_tag_offset = 0; - - while (preg_match(self::$tag, $this->content, $matches, PREG_OFFSET_CAPTURE, $this->offset)) { - $tag = $matches[1][0]; - - $startpos = $matches[0][1]; - $endpos = $matches[0][1] + strlen($matches[0][0]); - - switch($tag) { - case 'cached': - case 'uncached': - case 'cacheblock': - - $pretext = substr($this->content, $this->offset, $startpos - $this->offset); - $this->controlcheck($pretext); - $this->blocks[] = $pretext; - - if ($tag == 'cached' || $tag == 'cacheblock') { - list($keyparts, $conditional, $condition) = $this->parseargs(@$matches[2][0]); - $parser = new SSViewer_Cached_PartialParser($this->template, $this->content, $endpos, $keyparts, $conditional, $condition); - } - else { - $parser = new SSViewer_PartialParser($this->template, $this->content, $endpos); - } - - $parser->parse(); - $this->blocks[] = $parser; - $this->offset = $parser->offset; - break; - - case 'end_cached': - case 'end_cacheblock': - case 'end_uncached': - $this->blocks[] = substr($this->content, $this->offset, $startpos - $this->offset); - $this->content = null; - - $this->offset = $endpos; - return $this; - } - } - - $this->blocks[] = substr($this->content, $this->offset); - $this->content = null; - } - - function parseargs($string) { - preg_match_all(self::$argument_splitter, $string, $matches, PREG_SET_ORDER); - - $parts = array(); - $conditional = null; $condition = null; - - $current = '$item->'; - - while (strlen($string) && preg_match(self::$argument_splitter, $string, $match)) { - - $string = substr($string, strlen($match[0])); - - // If this is a conditional keyword, break, and the next loop will grab the conditional - if (@$match['conditional']) { - $conditional = $match['conditional']; - continue; - } - - // If it's a property lookup or a function call - if (@$match['property']) { - // Get the property - $what = $match['identifier']; - $args = array(); - - // Extract any arguments passed to the function call - if (@$match['arguments']) { - foreach (explode(',', $match['arguments']) as $arg) { - $args[] = is_numeric($arg) ? (string)$arg : '"'.$arg.'"'; - } - } - - $args = empty($args) ? 'null' : 'array('.implode(',',$args).')'; - - // If this fragment ended with '.', then there's another lookup coming, so return an obj for that lookup - if (@$match['fullstop']) { - $current .= "obj('$what', $args, true)->"; - } - // Otherwise this is the end of the lookup chain, so add the resultant value to the key array and reset the key-get php fragement - else { - $accessor = $current . "XML_val('$what', $args, true)"; $current = '$item->'; - - // If we've hit a conditional already, this is the condition. Set it and be done. - if ($conditional) { - $condition = $accessor; - break; - } - // Otherwise we're another key component. Add it to array. - else $parts[] = $accessor; - } - } - - // Else it's a quoted string of some kind - else if (@$match['sqstring']) $parts[] = $match['sqstring']; - else if (@$match['dqstring']) $parts[] = $match['dqstring']; - } - - if ($conditional && !$condition) { - throw new Exception("You need to have a condition after the conditional $conditional in your cache block"); - } - - return array($parts, $conditional, $condition); - } - - function generate() { - $res = array(); - - foreach ($this->blocks as $i => $block) { - if ($block instanceof SSViewer_PartialParser) - $res[] = $block->generate(); - else { - $res[] = $block; - } - } - - return implode('', $res); - } -} - -/** - * @package sapphire - * @subpackage view - */ -class SSViewer_Cached_PartialParser extends SSViewer_PartialParser { - - function __construct($template, $content, $offset, $keyparts, $conditional, $condition) { - $this->keyparts = $keyparts; - $this->conditional = $conditional; - $this->condition = $condition; - - parent::__construct($template, $content, $offset); - } - - function controlcheck($text) { - $ifs = preg_match_all('/<'.'% +if +/', $text, $matches); - $end_ifs = preg_match_all('/<'.'% +end_if +/', $text, $matches); - - if ($ifs != $end_ifs) throw new Exception('You can\'t have cached or uncached blocks within condition structures'); - - $controls = preg_match_all('/<'.'% +control +/', $text, $matches); - $end_controls = preg_match_all('/<'.'% +end_control +/', $text, $matches); - - if ($controls != $end_controls) throw new Exception('You can\'t have cached or uncached blocks within control structures'); - } - - function key() { - if (empty($this->keyparts)) return "''"; - return 'sha1(' . implode(".'_'.", $this->keyparts) . ')'; - } - - function generate() { - $res = array(); - $key = $this->key(); - - $condition = ""; - - switch ($this->conditional) { - case 'if': - $condition = "{$this->condition} && "; - break; - case 'unless': - $condition = "!({$this->condition}) && "; - break; - } - - /* Output this set of blocks */ - - foreach ($this->blocks as $i => $block) { - if ($block instanceof SSViewer_PartialParser) - $res[] = $block->generate(); - else { - // Include the template name and this cache block's current contents as a sha hash, so we get auto-seperation - // of cache blocks, and invalidation of the cache when the template changes - $partialkey = "'".sha1($this->template . $block)."_'.$key.'_$i'"; - - // Try to load from cache - $res[] = "load('.$partialkey.'))) $val .= $partial;'."\n"; - - // Cache miss - regenerate - $res[] = "else {\n"; - $res[] = '$oldval = $val; $val = "";'."\n"; - $res[] = "\n?>" . $block . "save($val); $val = $oldval . $val ;'."\n"; - $res[] = "}\n?>"; - } - } - - return implode('', $res); - } -} - -function supressOutput() { - return ""; -} - -?> \ No newline at end of file From 08faf036738f955430de312de5da39732b0838b9 Mon Sep 17 00:00:00 2001 From: Hamish Friedlander Date: Thu, 10 Mar 2011 17:38:03 +1300 Subject: [PATCH 15/15] BUGFIX: Fix href rewriting in text --- core/SSTemplateParser.php | 8 +++++++- core/SSTemplateParser.php.inc | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/core/SSTemplateParser.php b/core/SSTemplateParser.php index a34c953f8..14035bdaf 100644 --- a/core/SSTemplateParser.php +++ b/core/SSTemplateParser.php @@ -3699,10 +3699,16 @@ class SSTemplateParser extends Parser { */ function Text__finalise(&$res) { $text = $res['text']; + + // TODO: This is _super_ ugly, and a performance killer to boot. $text = preg_replace( '/href\s*\=\s*\"\#/', - 'href="#', + 'href="' . PHP_EOL . + 'SSVIEWER;' . PHP_EOL . + '$val .= SSViewer::$options[\'rewriteHashlinks\'] ? Convert::raw2att( $_SERVER[\'REQUEST_URI\'] ) : "";' . PHP_EOL . + '$val .= <<#', + 'href="' . PHP_EOL . + 'SSVIEWER;' . PHP_EOL . + '$val .= SSViewer::$options[\'rewriteHashlinks\'] ? Convert::raw2att( $_SERVER[\'REQUEST_URI\'] ) : "";' . PHP_EOL . + '$val .= <<