Skip to content

Commit

Permalink
fix parsing to pass tests
Browse files Browse the repository at this point in the history
  • Loading branch information
matronator committed Jun 5, 2024
1 parent d24ceb5 commit 58ba4c7
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 17 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
vendor
parsem.sketch
.DS_Store
dump.log
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"autoload": {
"psr-4": {
"Matronator\\Parsem\\": ["src/Parsem/"]
}
},
"files": ["helpers.php"]
},
"authors": [
{
Expand Down
9 changes: 9 additions & 0 deletions helpers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

if (!function_exists('dump')) {
function dump($var)
{
$logFile = __DIR__ . '/dump.log';
file_put_contents($logFile, print_r($var, true) . PHP_EOL, FILE_APPEND | LOCK_EX);
}
}
72 changes: 57 additions & 15 deletions src/Parsem/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ final class Parser
* 3: filter:10,'arg','another' --> (filter with args)
* 4: filter --> (only filter name)
*/
public const VARIABLE_PATTERN = '/<%\s?([a-zA-Z0-9_]+)(=.+?)?\|?(([a-zA-Z0-9_]+?)(?:\:(?:(?:\\?\'|\\?")?.?(?:\\?\'|\\?")?,?)+?)*?)?\s?%>/m';
public const VARIABLE_PATTERN = '/<%\s?((?!endif|else)[a-zA-Z0-9_]+)(=.+?)?\|?(([a-zA-Z0-9_]+?)(?:\:(?:(?:\\?\'|\\?")?.?(?:\\?\'|\\?")?,?)+?)*?)?\s?%>/m';

/**
* Matches:
Expand Down Expand Up @@ -86,6 +86,61 @@ public static function parseConditions(string $string, array $arguments = [], in
return $string;
}

$result = static::getConditionResult($matches, $arguments);

$conditionStart = $matches[0][1];
$conditionLength = strlen($matches[0][0]);

$nestedIfs = preg_match_all(static::CONDITION_PATTERN, $string, $nestedMatches, PREG_OFFSET_CAPTURE, $offset + $conditionLength);
if ($nestedIfs > 0) {
$string = self::parseConditions($string, $arguments, (int)$conditionStart + (int)$conditionLength, $offset);
}

$hasElse = false;

$elseCount = preg_match('/<%\s?else\s?%>\n?/', $string, $elseMatches, PREG_OFFSET_CAPTURE, $offset);
if ($elseCount !== false && $elseCount === 1 && $elseMatches) {
$hasElse = true;
preg_match('/<%\s?endif\s?%>\n?/', $string, $endMatches, PREG_OFFSET_CAPTURE, $offset);
if (!$endMatches) {
throw new RuntimeException("Missing <% endif %> tag.");
}

$elseStart = $elseMatches[0][1];
$elseTagLength = strlen($elseMatches[0][0]);
$conditionEnd = $endMatches[0][1];

$elseBlock = substr($string, $elseStart + $elseTagLength, $conditionEnd - $elseStart - $elseTagLength);
} else if ($elseCount > 1) {
throw new RuntimeException("Too many <% else %> tags.");
}

preg_match('/<%\s?endif\s?%>\n?/', $string, $endMatches, PREG_OFFSET_CAPTURE, $offset);
if (!$endMatches) {
throw new RuntimeException("Missing <% endif %> tag.");
}


if ($hasElse) {
$conditionEnd = $endMatches[0][1];
$insideBlock = substr($string, $conditionStart + $conditionLength, $elseStart - $conditionStart - $conditionLength);
$string = substr_replace($string, $result ? $insideBlock : $elseBlock, (int)$conditionStart, $conditionEnd - $conditionStart + strlen($endMatches[0][0]));
} else {
$conditionEnd = $endMatches[0][1];
$insideBlock = substr($string, $conditionStart + $conditionLength, $conditionEnd - $conditionStart - $conditionLength);
$string = substr_replace($string, $result ? $insideBlock : '', (int)$conditionStart, $conditionEnd - $conditionStart + strlen($endMatches[0][0]));
}

preg_match(static::CONDITION_PATTERN, $string, $matches, PREG_OFFSET_CAPTURE, $offset);
if (!$matches) {
return $string;
}

return self::parseConditions($string, $arguments, (int)$conditionStart);
}

public static function getConditionResult(array $matches, array $arguments = []): bool
{
$left = $matches['left'][0];
$negation = $matches['negation'][0] ?? null;
$operator = $matches['operator'][0] ?? null;
Expand Down Expand Up @@ -182,20 +237,7 @@ public static function parseConditions(string $string, array $arguments = [], in
$result = $left;
}

preg_match('/<%\s?endif\s?%>\n?/', $string, $endMatches, PREG_OFFSET_CAPTURE, $offset);
if (!$endMatches) {
throw new RuntimeException("Missing <% endif %> tag.");
}

$insideBlock = substr($string, $matches[0][1] + strlen($matches[0][0]), $endMatches[0][1] - $matches[0][1] - strlen($matches[0][0]));
$string = substr_replace($string, $result ? $insideBlock : '', (int)$matches[0][1], $endMatches[0][1] - $matches[0][1] + strlen($endMatches[0][0]));

preg_match(static::CONDITION_PATTERN, $string, $matches, PREG_OFFSET_CAPTURE, $offset);
if (!$matches) {
return $string;
}

return self::parseConditions($string, $arguments, (int)$matches[0][1]);
return $result;
}

/**
Expand Down
17 changes: 17 additions & 0 deletions tests/Parsem/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,23 @@ public function testNewLines()
Assert::equal($expected, $parsed, '(false) New lines are ignored.');
Assert::equal($expected2, $parsed2, '(true) New lines are ignored.');
}

/** @testCase */
public function testElseBlocks()
{
$string = "Hello<% if false %> Amazing<% else %> Cruel<% endif %> World!";

$expected = "Hello Cruel World!";

$string2 = "Hello<% if true %> Amazing<% else %> Cruel<% endif %> World!";

$expected2 = "Hello Amazing World!";

$parsed = Parser::parseString($string, []);
$parsed2 = Parser::parseString($string2, []);
Assert::equal($expected, $parsed, '(false) Else block is parsed.');
Assert::equal($expected2, $parsed2, '(true) If block is parsed.');
}
}

(new ParserTest())->run();
4 changes: 3 additions & 1 deletion tests/Parsem/output/ParserTest.actual
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
Hello

<% if false %>
Amazing
Cruel
World!
1 change: 1 addition & 0 deletions tests/Parsem/output/ParserTest.expected
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Hello
Cruel
World!

0 comments on commit 58ba4c7

Please sign in to comment.