From 5111b56ac9b0a90a8252a25864b5056664f8a66b Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Thu, 15 Sep 2022 12:59:05 +1200 Subject: [PATCH] ENH Add PHP 8.1 safe null-coalescing operators to peg file --- src/View/SSTemplateParser.peg | 76 ++++++++++++++++----------------- src/View/SSTemplateParser.php | 2 +- thirdparty/php-peg/Compiler.php | 2 +- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/View/SSTemplateParser.peg b/src/View/SSTemplateParser.peg index 0fd61dafa..b58e44b95 100644 --- a/src/View/SSTemplateParser.peg +++ b/src/View/SSTemplateParser.peg @@ -247,7 +247,7 @@ class SSTemplateParser extends Parser implements TemplateParser } $res['php'] .= ($sub['ArgumentMode'] == 'default') ? $sub['string_php'] : - str_replace('$$FINAL', 'XML_val', $sub['php']); + str_replace('$$FINAL', 'XML_val', $sub['php'] ?? ''); } /*!* @@ -356,13 +356,13 @@ class SSTemplateParser extends Parser implements TemplateParser function InjectionVariables_Argument(&$res, $sub) { - $res['php'] .= str_replace('$$FINAL', 'XML_val', $sub['php']) . ','; + $res['php'] .= str_replace('$$FINAL', 'XML_val', $sub['php'] ?? '') . ','; } function InjectionVariables__finalise(&$res) { - if (substr($res['php'], -1) == ',') { - $res['php'] = substr($res['php'], 0, -1); //remove last comma in the array + if (substr($res['php'] ?? '', -1) == ',') { + $res['php'] = substr($res['php'] ?? '', 0, -1); //remove last comma in the array } $res['php'] .= ']'; } @@ -391,7 +391,7 @@ class SSTemplateParser extends Parser implements TemplateParser */ function Injection_STR(&$res, $sub) { - $res['php'] = '$val .= '. str_replace('$$FINAL', 'XML_val', $sub['Lookup']['php']) . ';'; + $res['php'] = '$val .= '. str_replace('$$FINAL', 'XML_val', $sub['Lookup']['php'] ?? '') . ';'; } /*!* @@ -456,12 +456,12 @@ class SSTemplateParser extends Parser implements TemplateParser function Argument_QuotedString(&$res, $sub) { $res['ArgumentMode'] = 'string'; - $res['php'] = "'" . str_replace("'", "\\'", $sub['String']['text']) . "'"; + $res['php'] = "'" . str_replace("'", "\\'", $sub['String']['text'] ?? '') . "'"; } function Argument_Lookup(&$res, $sub) { - if (count($sub['LookupSteps']) == 1 && !isset($sub['LookupSteps'][0]['Call']['Arguments'])) { + 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']."'"; @@ -474,7 +474,7 @@ class SSTemplateParser extends Parser implements TemplateParser function Argument_FreeString(&$res, $sub) { $res['ArgumentMode'] = 'string'; - $res['php'] = "'" . str_replace("'", "\\'", trim($sub['text'])) . "'"; + $res['php'] = "'" . str_replace("'", "\\'", trim($sub['text'] ?? '')) . "'"; } /*!* @@ -491,10 +491,10 @@ class SSTemplateParser extends Parser implements TemplateParser if (!empty($res['php'])) { $res['php'] .= $sub['string_php']; } else { - $res['php'] = str_replace('$$FINAL', 'XML_val', $sub['lookup_php']); + $res['php'] = str_replace('$$FINAL', 'XML_val', $sub['lookup_php'] ?? ''); } } else { - $res['php'] .= str_replace('$$FINAL', 'XML_val', $sub['php']); + $res['php'] .= str_replace('$$FINAL', 'XML_val', $sub['php'] ?? ''); } } @@ -524,7 +524,7 @@ class SSTemplateParser extends Parser implements TemplateParser $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 ?? ''); } } @@ -630,7 +630,7 @@ class SSTemplateParser extends Parser implements TemplateParser function CacheBlockArgument_QuotedString(&$res, $sub) { - $res['php'] = "'" . str_replace("'", "\\'", $sub['String']['text']) . "'"; + $res['php'] = "'" . str_replace("'", "\\'", $sub['String']['text'] ?? '') . "'"; } function CacheBlockArgument_Lookup(&$res, $sub) @@ -653,7 +653,7 @@ class SSTemplateParser extends Parser implements TemplateParser $res['php'] = ''; } - $res['php'] .= str_replace('$$FINAL', 'XML_val', $sub['php']); + $res['php'] .= str_replace('$$FINAL', 'XML_val', $sub['php'] ?? ''); } /*!* @@ -749,7 +749,7 @@ class SSTemplateParser extends Parser implements TemplateParser $res['php'] .= 'return $val;' . PHP_EOL; $res['php'] .= '};' . PHP_EOL; $key = 'sha1($keyExpression())' // Global key - . '.\'_' . sha1($sub['php']) // sha of template + . '.\'_' . sha1($sub['php'] ?? '') // sha of template . (isset($res['key']) && $res['key'] ? "_'.sha1(".$res['key'].")" : "'") // Passed key . ".'_$block'"; // block index // Get any condition @@ -782,7 +782,7 @@ class SSTemplateParser extends Parser implements TemplateParser function OldTPart_QuotedString(&$res, $sub) { $entity = $sub['String']['text']; - if (strpos($entity, '.') === false) { + if (strpos($entity ?? '', '.') === false) { $res['php'] .= "\$scope->XML_val('I18NNamespace').'.$entity'"; } else { $res['php'] .= "'$entity'"; @@ -871,7 +871,7 @@ class SSTemplateParser extends Parser implements TemplateParser break; default: - $res['php'] .= str_replace('$$FINAL', 'obj', $sub['php']) . '->self()'; + $res['php'] .= str_replace('$$FINAL', 'obj', $sub['php'] ?? '') . '->self()'; break; } } @@ -909,9 +909,9 @@ class SSTemplateParser extends Parser implements TemplateParser if ($this->includeDebuggingComments) { // Add include filename comments on dev sites $res['php'] = - '$val .= \'\';'. "\n". + '$val .= \'\';'. "\n". $res['php']. - '$val .= \'\';'. "\n"; + '$val .= \'\';'. "\n"; } } @@ -962,7 +962,7 @@ class SSTemplateParser extends Parser implements TemplateParser $res['ArgumentCount'] = 1; } else { $res['Arguments'] = $sub['Argument']; - $res['ArgumentCount'] = count($res['Arguments']); + $res['ArgumentCount'] = count($res['Arguments'] ?? []); } } @@ -971,7 +971,7 @@ class SSTemplateParser extends Parser implements TemplateParser $blockname = $res['BlockName']['text']; $method = 'ClosedBlock_Handle_'.$blockname; - if (method_exists($this, $method)) { + if (method_exists($this, $method ?? '')) { $res['php'] = $this->$method($res); } elseif (isset($this->closedBlocks[$blockname])) { $res['php'] = call_user_func($this->closedBlocks[$blockname], $res); @@ -1053,7 +1053,7 @@ class SSTemplateParser extends Parser implements TemplateParser $res['ArgumentCount'] = 1; } else { $res['Arguments'] = $sub['Argument']; - $res['ArgumentCount'] = count($res['Arguments']); + $res['ArgumentCount'] = count($res['Arguments'] ?? []); } } @@ -1062,7 +1062,7 @@ class SSTemplateParser extends Parser implements TemplateParser $blockname = $res['BlockName']['text']; $method = 'OpenBlock_Handle_'.$blockname; - if (method_exists($this, $method)) { + if (method_exists($this, $method ?? '')) { $res['php'] = $this->$method($res); } elseif (isset($this->openBlocks[$blockname])) { $res['php'] = call_user_func($this->openBlocks[$blockname], $res); @@ -1087,7 +1087,7 @@ class SSTemplateParser extends Parser implements TemplateParser } $php = ($arg['ArgumentMode'] == 'default') ? $arg['lookup_php'] : $arg['php']; - return '$val .= Debug::show('.str_replace('FINALGET!', 'cachedCall', $php).');'; + return '$val .= Debug::show('.str_replace('FINALGET!', 'cachedCall', $php ?? '').');'; } else { throw new SSTemplateParseException('Debug takes 0 or 1 argument only.', $this); } @@ -1221,8 +1221,8 @@ class SSTemplateParser extends Parser implements TemplateParser $text = $res['text']; // Unescape any escaped characters in the text, then put back escapes for any single quotes and backslashes - $text = stripslashes($text); - $text = addcslashes($text, '\'\\'); + $text = stripslashes($text ?? ''); + $text = addcslashes($text ?? '', '\'\\'); // TODO: This is pretty ugly & gets applied on all files not just html. I wonder if we can make this // non-dynamically calculated @@ -1234,8 +1234,8 @@ EOC; // Because preg_replace replacement requires escaped slashes, addcslashes here $text = preg_replace( '/(]+href *= *)"#/i', - '\\1"\' . ' . addcslashes($code, '\\') . ' . \'#', - $text + '\\1"\' . ' . addcslashes($code ?? '', '\\') . ' . \'#', + $text ?? '' ); $res['php'] .= '$val .= \'' . $text . '\';' . PHP_EOL; @@ -1257,7 +1257,7 @@ EOC; */ public function compileString($string, $templateName = "", $includeDebuggingComments = false, $topTemplate = true) { - if (!trim($string)) { + if (!trim($string ?? '')) { $code = ''; } else { parent::__construct($string); @@ -1266,7 +1266,7 @@ EOC; // Ignore UTF8 BOM at beginning 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)) { + if (substr($string ?? '', 0, 3) == pack("CCC", 0xef, 0xbb, 0xbf)) { $this->pos = 3; } @@ -1285,7 +1285,7 @@ EOC; } // Include top level debugging comments if desired - if ($includeDebuggingComments && $templateName && stripos($code, "includeDebuggingComments($code, $templateName); } @@ -1301,12 +1301,12 @@ EOC; { // If this template contains a doctype, put it right after it, // if not, put it after the tag to avoid IE glitches - if (stripos($code, "]*("[^"]")*[^>]*>)/im', "$1\r\n", $code); + if (stripos($code ?? '', "]*("[^"]")*[^>]*>)/im', "$1\r\n", $code ?? ''); $code .= "\r\n" . '$val .= \'\';'; - } elseif (stripos($code, "]*>)(.*)/i', function ($matches) use ($templateName) { - if (stripos($matches[3], '') !== false) { + if (stripos($matches[3] ?? '', '') !== false) { // after this tag there is a comment close but no comment has been opened // this most likely means that this tag is inside a comment // we should not add a comment inside a comment (invalid html) @@ -1317,11 +1317,11 @@ EOC; // all other cases, add the comment and return it return "{$matches[1]}{$matches[2]}{$matches[3]}"; } - }, $code); - $code = preg_replace('/(<\/html[^>]*>)/i', "$1", $code); + }, $code ?? ''); + $code = preg_replace('/(<\/html[^>]*>)/i', "$1", $code ?? ''); } else { $code = str_replace('\';' . "\r\n", $code); + ' -->\';' . "\r\n", $code ?? ''); $code .= "\r\n" . '$val .= \'\';'; } return $code; @@ -1337,6 +1337,6 @@ EOC; */ public function compileFile($template) { - return $this->compileString(file_get_contents($template), $template); + return $this->compileString(file_get_contents($template ?? ''), $template); } } diff --git a/src/View/SSTemplateParser.php b/src/View/SSTemplateParser.php index b5c602c19..2dabc1db4 100644 --- a/src/View/SSTemplateParser.php +++ b/src/View/SSTemplateParser.php @@ -3501,7 +3501,7 @@ class SSTemplateParser extends Parser implements TemplateParser break; default: - $res['php'] .= str_replace('$$FINAL', 'obj', $sub['php']) . '->self()'; + $res['php'] .= str_replace('$$FINAL', 'obj', $sub['php'] ?? '') . '->self()'; break; } } diff --git a/thirdparty/php-peg/Compiler.php b/thirdparty/php-peg/Compiler.php index 3bc523b57..07a08c721 100644 --- a/thirdparty/php-peg/Compiler.php +++ b/thirdparty/php-peg/Compiler.php @@ -276,7 +276,7 @@ class TokenLiteral extends TokenExpressionable { function match_code( $value ) { // We inline single-character matches for speed if ( !$this->contains_expression($value) && strlen( eval( 'return '. $value . ';' ) ) == 1 ) { - return $this->match_fail_conditional( 'substr($this->string,$this->pos,1) == '.$value, + return $this->match_fail_conditional( 'substr($this->string ?? \'\',$this->pos ?? 0,1) == '.$value, PHPBuilder::build()->l( '$this->pos += 1;', $this->set_text($value)