160 lines
4.5 KiB
PHP
160 lines
4.5 KiB
PHP
<?php namespace SokoWeb\View;
|
|
|
|
class Parser
|
|
{
|
|
private string $file;
|
|
|
|
public function __construct(string $file)
|
|
{
|
|
$this->file = $file;
|
|
}
|
|
|
|
public function parse(): ParsedFragment
|
|
{
|
|
$sectionOpen = null;
|
|
$extraOpen = false;
|
|
|
|
$extends = null;
|
|
$js = [];
|
|
$css = [];
|
|
$sections = [];
|
|
$extra = ['', ''];
|
|
|
|
$fileHandle = fopen($this->file, 'r');
|
|
if (!$fileHandle) {
|
|
throw new \Exception('Cannot open file ' . $this->file);
|
|
}
|
|
|
|
$lineNumber = 0;
|
|
while (($line = fgets($fileHandle)) !== false) {
|
|
++$lineNumber;
|
|
|
|
if (($cssMatched = $this->matchCss($line)) !== null) {
|
|
$css[] = $cssMatched;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (($jsMatched = $this->matchJs($line)) !== null) {
|
|
$js[] = $jsMatched;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (($extendsMatched = $this->matchExtends($line)) !== null) {
|
|
if ($extends !== null) {
|
|
throw new \Exception('Error in file ' . $this->file . ' in line ' . $lineNumber . ' - There is already an \'@extends\' declared.');
|
|
}
|
|
|
|
$extends = $extendsMatched;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (($sectionMatched = $this->matchSection($line)) !== null) {
|
|
if ($extends === null) {
|
|
throw new \Exception('Error in file ' . $this->file . ' in line ' . $lineNumber . ' - \'@section\' has no meaning if view extends nothing.');
|
|
}
|
|
if ($sectionOpen !== null) {
|
|
throw new \Exception('Parse error in file ' . $this->file . ' in line ' . $lineNumber . ' - A \'@section\' is already open (no \'@endsection\' found).');
|
|
}
|
|
|
|
$sectionOpen = $sectionMatched;
|
|
$sections[$sectionOpen] = '';
|
|
|
|
continue;
|
|
}
|
|
|
|
if ($this->matchEndSection($line)) {
|
|
if ($sectionOpen === null) {
|
|
throw new \Exception('Parse error in file ' . $this->file . ' in line ' . $lineNumber . ' - Cannot end section until no \'@section\' is open.');
|
|
}
|
|
|
|
$sectionOpen = null;
|
|
}
|
|
|
|
if ($this->matchExtra($line)) {
|
|
if ($extraOpen) {
|
|
throw new \Exception('Parse error in file ' . $this->file . ' in line ' . $lineNumber . ' - An \'@extra\' is already open (no \'@endextra\' found).');
|
|
}
|
|
|
|
$extraOpen = true;
|
|
|
|
continue;
|
|
}
|
|
|
|
if ($this->matchEndExtra($line)) {
|
|
if (!$extraOpen) {
|
|
throw new \Exception('Parse error in file ' . $this->file . ' in line ' . $lineNumber . ' - Cannot end extra until no \'@extra\' is open.');
|
|
}
|
|
|
|
$extraOpen = false;
|
|
}
|
|
|
|
if ($sectionOpen !== null) {
|
|
$sections[$sectionOpen] .= $line;
|
|
}
|
|
|
|
if ($extraOpen) {
|
|
$offset = $extends === null ? 0 : 1;
|
|
$extra[$offset] .= $line;
|
|
}
|
|
}
|
|
|
|
fclose($fileHandle);
|
|
|
|
return new ParsedFragment($extends, $css, $js, $sections, $extra);
|
|
}
|
|
|
|
private function matchCss(string $line): ?string
|
|
{
|
|
if (preg_match('/^\s*@css\((.*)\)\s*$/', $line, $matches) === 1) {
|
|
return $matches[1];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function matchJs(string $line): ?string
|
|
{
|
|
if (preg_match('/^\s*@js\((.*)\)\s*$/', $line, $matches) === 1) {
|
|
return $matches[1];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function matchExtends(string $line): ?string
|
|
{
|
|
if (preg_match('/^\s*@extends\(([\w\/]+)\)\s*$/', $line, $matches) === 1) {
|
|
return $matches[1];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function matchSection(string $line): ?string
|
|
{
|
|
if (preg_match('/^\s*@section\((\w+)\)\s*$/', $line, $matches) === 1) {
|
|
return $matches[1];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function matchEndSection(string $line): bool
|
|
{
|
|
return preg_match('/^\s*@endsection(?:\(\))?\s*$/', $line) === 1;
|
|
}
|
|
|
|
private function matchExtra(string $line): bool
|
|
{
|
|
return preg_match('/^\s*@extra(?:\(\))?\s*$/', $line) === 1;
|
|
}
|
|
|
|
private function matchEndExtra(string $line): bool
|
|
{
|
|
return preg_match('/^\s*@endextra(?:\(\))?\s*$/', $line) === 1;
|
|
}
|
|
}
|