Skip to content

Commit

Permalink
Merge pull request #2 from csrdelft/two-stage-parser
Browse files Browse the repository at this point in the history
Split bb parser into two stages.
  • Loading branch information
qurben authored Jan 21, 2021
2 parents 707ae71 + e967400 commit 19e69d4
Show file tree
Hide file tree
Showing 32 changed files with 404 additions and 148 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.idea
vendor
vendor

.phpunit.result.cache
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ Tags must extend the `\CsrDelft\bb\BbTag` class. Tags must implement the `parse(

The `getTagName` method retuns a string or list of strings with the name(s) of this tag.

The `parse` method receives a map of arguments. The `getContent` method can be used to retrieve the contents of
The `parse` method receives a map of arguments. The `readContent` method can be used to retrieve the contents of
the tag, this content is parsed by the parser when it is received. The parser reads the input until an end tag is
found. `getContent` has an optional parameter for tags which are forbidden to be in this tag. For instance a `[sup]`
found. `readContent` has an optional parameter for tags which are forbidden to be in this tag. For instance a `[sup]`
tag cannot contain another sup tag or a sub tag.

A tag has access to an environment, which is by default of type `CsrDelft\bb\BBenv` (can be overridden).
Expand All @@ -73,11 +73,11 @@ class BbSuperscript extends BbTag {
}

public function render() {
return '<sup class="bb-tag-sup">' . $this->content . '</sup>';
return '<sup class="bb-tag-sup">' . $this->getContent() . '</sup>';
}

public function parse($arguments = []) {
$this->readContent(['sub', 'sup'])
$this->readContent(['sub', 'sup']);
}
}
```
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
},
"autoload": {
"psr-4": {
"CsrDelft\\bb\\": "src/"
"CsrDelft\\bb\\": "src/",
"CsrDelft\\bb\\test\\": "tests/lib/"
}
},
"scripts": {
Expand Down
156 changes: 101 additions & 55 deletions src/BbTag.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<?php

namespace CsrDelft\bb;

use CsrDelft\bb\tag\BbNode;
use Error;
use stdClass;

abstract class BbTag {
abstract class BbTag implements BbNode
{
/**
* @var Parser
*/
Expand All @@ -18,20 +21,27 @@ abstract class BbTag {
protected $env;
/**
* The content of the tag. Is empty at parse time. Can be filled by calling readContent()
* @var $content
* @var string|null
*/
private $content = null;
/**
* @var BbNode[]|null
*/
protected $content = null;
private $children;

public function setParser(Parser $parser) {
$this->parser = $parser;
public static function isParagraphLess()
{
return false;
}

public function setEnv($env) {
$this->env = $env;
public function setParser(Parser $parser)
{
$this->parser = $parser;
}

public static function isParagraphLess() {
return false;
public function setEnv($env)
{
$this->env = $env;
}

public function isAllowed()
Expand All @@ -40,80 +50,111 @@ public function isAllowed()
}

/**
* Read from the parser.
*
* NOTE: this consumes the input string.
* @param array $arguments
* @return mixed
* @throws BbException
*/
abstract public function parse($arguments = []);

/**
* @return BbNode[]|null
*/
public function getChildren()
{
return $this->children;
}

/**
* @param BbNode[] $children
*/
public function setChildren($children)
{
$this->children = $children;
}

public function getContent()
{
return $this->content;
}

public function setContent($content)
{
$this->content = $content;
}

/**
* ParseLight defaults to parse
*
* @param string[] $forbidden Tag names that cannot exist in this tag.
* @return mixed
* @throws BbException
*/
protected function readContent($forbidden = [], $parse_bb = true) {
if ($this->content != NULL)
throw new Error("Can not call readContent twice on the same tag");
$stoppers = $this->getStoppers();
$parse_bb_state_before = $this->parser->bb_mode;
$this->parser->bb_mode &= $parse_bb;
public function renderLight()
{
return $this->render();
}

$result = $this->parser->parseArray($stoppers, $forbidden);
abstract public function render();

$this->parser->bb_mode = $parse_bb_state_before;
$this->content = $result;
/**
* render plain will strip html tags by default.
*
* @return string
*/
public function renderPlain()
{
return strip_tags($this->render());
}

/**
* Get the main argument for this tag and put it in $this->content.
* Get the main argument for this tag and return it.
*
* [tag=123] or [tag]123[/tag]
*
* @param $arguments
* @return string
*/
protected function readMainArgument($arguments) {
protected function readMainArgument($arguments)
{
if (is_array($this->getTagName())) {
foreach ($this->getTagName() as $tagName) {
if (isset($arguments[$tagName])) {
$this->content = trim($arguments[$tagName]);
return trim($arguments[$tagName]);
}
}

return '';
} elseif (isset($arguments[$this->getTagName()])) {
$this->content = trim($arguments[$this->getTagName()]);
}
else {
return trim($arguments[$this->getTagName()]);
} else {
$this->readContent([], false);
$this->content = trim($this->content);
// parse_bb is disabled in readContent, so all nodes should be BbString
return trim(implode(array_map(function (BbNode $node) {
return $node->render();
}, $this->children)));
}
}

private function createStopper($tagName) {
return "[/$tagName]";
}

abstract public static function getTagName();

/**
* @param array $arguments
* @return mixed
* @throws BbException
*/
abstract public function parse($arguments = []);

abstract public function render();

/**
* ParseLight defaults to parse
* Read from the parser.
*
* @return mixed
* @throws BbException
*/
public function renderLight() {
return $this->render();
}

/**
* render plain will strip html tags by default.
* NOTE: this consumes the input string.
*
* @return string
* @param string[] $forbidden Tag names that cannot exist in this tag.
*/
public function renderPlain() {
return strip_tags($this->render());
protected function readContent($forbidden = [], $parse_bb = true)
{
if ($this->content != NULL)
throw new Error("Can not call readContent twice on the same tag");
$stoppers = $this->getStoppers();
$parse_bb_state_before = $this->parser->bb_mode;
$this->parser->bb_mode &= $parse_bb;

$result = $this->parser->parseArray($stoppers, $forbidden);

$this->parser->bb_mode = $parse_bb_state_before;
$this->children = $result;
}

protected function getStoppers()
Expand All @@ -130,4 +171,9 @@ protected function getStoppers()
$stoppers[] = $this->createStopper('');
return $stoppers;
}

private function createStopper($tagName)
{
return "[/$tagName]";
}
}
Loading

0 comments on commit 19e69d4

Please sign in to comment.