Skip to content
29 changes: 21 additions & 8 deletions spec/Lexer/LexerSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public function it_can_switch_state(): void

$this->getState()->shouldReturn($origState);

$this->setState($newState);
$this->pushState($newState);

$this->getState()->shouldReturn($newState);
}
Expand All @@ -67,8 +67,21 @@ public function it_records_previous_states(): void

$this->beConstructedWith($origState);

$this->pushState($newState);

$this->getLastState()->shouldReturn($origState);
}

public function it_keeps_set_state_as_an_alias_for_push_state(): void
{
$origState = new InitialState();
$newState = new InitialState();

$this->beConstructedWith($origState);

$this->setState($newState);

$this->getState()->shouldReturn($newState);
$this->getLastState()->shouldReturn($origState);
}

Expand All @@ -85,8 +98,8 @@ public function it_pops_back_to_the_previous_state(): void

$this->beConstructedWith($firstState);

$this->setState($secondState);
$this->setState($thirdState);
$this->pushState($secondState);
$this->pushState($thirdState);

$this->popState();

Expand All @@ -110,7 +123,7 @@ public function it_gives_the_same_tokens_when_tokenising_the_same_text_twice():
$newState = new InitialState();

$origState->registerMatcher(new LexerSpecRegexMatcher('Letter', '/(?<all>a)/A'), function (Lexer $lexer) use ($newState): void {
$lexer->setState($newState);
$lexer->pushState($newState);
});
$newState->registerMatcher(new LexerSpecRegexMatcher('Other', '/(?<all>a)/A'));

Expand All @@ -126,7 +139,7 @@ public function it_restores_the_initial_state_after_tokenising(): void
$newState = new InitialState();

$origState->registerMatcher(new LexerSpecRegexMatcher('Letter', '/(?<all>a)/A'), function (Lexer $lexer) use ($newState): void {
$lexer->setState($newState);
$lexer->pushState($newState);
});

$this->beConstructedWith($origState);
Expand Down Expand Up @@ -157,7 +170,7 @@ public function it_switches_state_on_a_zero_length_lookahead_match(): void

$origState->registerMatcher(new LexerSpecRegexMatcher('Letter', '/(?<all>a)/A'));
$origState->registerMatcher(new LexerSpecRegexMatcher('Lookahead', '/(?<all>)(?=b)/A'), function (Lexer $lexer) use ($newState): void {
$lexer->setState($newState);
$lexer->pushState($newState);
});
$newState->registerMatcher(new LexerSpecRegexMatcher('Rest', '/(?<all>b+)/A'));

Expand All @@ -182,10 +195,10 @@ public function it_throws_if_zero_length_matches_return_to_a_state_without_advan
$secondState = new InitialState();

$firstState->registerMatcher(new LexerSpecRegexMatcher('ToSecond', '/(?<all>)/A'), function (Lexer $lexer) use ($secondState): void {
$lexer->setState($secondState);
$lexer->pushState($secondState);
});
$secondState->registerMatcher(new LexerSpecRegexMatcher('ToFirst', '/(?<all>)/A'), function (Lexer $lexer) use ($firstState): void {
$lexer->setState($firstState);
$lexer->pushState($firstState);
});

$this->beConstructedWith($firstState);
Expand Down
3 changes: 2 additions & 1 deletion spec/Token/TokenSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace spec\chrisjenkinson\StructuredDocumentParser\Token;

use chrisjenkinson\StructuredDocumentParser\Token\NonexistentKeyException;
use chrisjenkinson\StructuredDocumentParser\Token\TokenPosition;
use PhpSpec\ObjectBehavior;

Expand All @@ -26,7 +27,7 @@ public function it_has_values(): void

public function it_throws_an_exception_if_no_key(): void
{
$this->shouldThrow(\RuntimeException::class)->duringGetValue('nonexistent');
$this->shouldThrow(NonexistentKeyException::class)->duringGetValue('nonexistent');
}

public function it_can_return_all_values(): void
Expand Down
12 changes: 3 additions & 9 deletions src/Finder/RegexFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,12 @@
class RegexFinder
{
/**
* @var string
* @var mixed[]
*/
private $pattern;
private array $matches = [];

/**
* @var array
*/
private $matches = [];

public function __construct(string $pattern)
public function __construct(private readonly string $pattern)
{
$this->pattern = $pattern;
}

public function find(string $text): bool
Expand Down
46 changes: 12 additions & 34 deletions src/Lexer/Cursor.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,19 @@

class Cursor
{
/**
* @var int
*/
private $currentPosition;

/**
* @var int
*/
private $textLength;

/**
* @var string
*/
private $text;

/**
* @var int
*/
private $line = 1;

/**
* @var int
*/
private $column = 1;

/**
* @var int
*/
private $byteOffset = 0;

public function __construct(string $text)
private int $currentPosition = 0;

private readonly int $textLength;

private int $line = 1;

private int $column = 1;

private int $byteOffset = 0;

public function __construct(private readonly string $text)
{
$this->text = $text;
$this->currentPosition = 0;
$this->textLength = mb_strlen($text);
$this->textLength = mb_strlen($text);
}

public function getRemainingText(): string
Expand Down
27 changes: 13 additions & 14 deletions src/Lexer/Lexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,16 @@

class Lexer
{
/**
* @var StateInterface
*/
private $initialState;

/**
* @var StateInterface
*/
private $state;
private StateInterface $state;

/**
* @var StateInterface[]
*/
private $previousStates = [];
private array $previousStates = [];

public function __construct(StateInterface $initialState)
public function __construct(private readonly StateInterface $initialState)
{
$this->initialState = $initialState;
$this->state = $initialState;
$this->state = $initialState;
}

public function tokenise(string $text): TokenStream
Expand All @@ -52,12 +43,20 @@ public function getState(): StateInterface
* States are compared by identity when detecting zero-length token loops, so reuse
* state instances rather than creating new ones on each switch.
*/
public function setState(StateInterface $state): void
public function pushState(StateInterface $state): void
{
$this->previousStates[] = $this->state;
$this->state = $state;
}

/**
* @deprecated use pushState()
*/
public function setState(StateInterface $state): void
{
$this->pushState($state);
}

public function getLastState(): StateInterface
{
if ([] === $this->previousStates) {
Expand Down
7 changes: 2 additions & 5 deletions src/Matcher/MatchedText.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,10 @@
class MatchedText
{
/**
* @var mixed[]
* @param mixed[] $matches
*/
private $matches;

public function __construct(array $matches)
public function __construct(private readonly array $matches)
{
$this->matches = $matches;
}

/**
Expand Down
9 changes: 2 additions & 7 deletions src/Matcher/SimpleTextMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,11 @@

class SimpleTextMatcher extends AbstractMatcher
{
/**
* @var RegexFinder
*/
private $finder;
private readonly RegexFinder $finder;

public function __construct()
{
$pattern = '/(?<all>.+)/As';

$this->finder = new RegexFinder($pattern);
$this->finder = new RegexFinder('/(?<all>.+)/As');
}

public function match(string $text): ?MatchedText
Expand Down
15 changes: 5 additions & 10 deletions src/Node/AbstractNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
abstract class AbstractNode implements NodeInterface
{
/**
* @var array
* @var array<string, mixed>
*/
protected $attributes = [];
protected array $attributes = [];

/**
* @var NodeInterface[]
*/
protected $nodes = [];
protected array $nodes = [];

public function __toString(): string
{
Expand All @@ -32,12 +32,7 @@ public function jsonSerialize(): array
return ['attributes' => $this->attributes, 'nodes' => $this->nodes];
}

/**
* @param string $key
*
* @return mixed
*/
public function getAttribute(string $key)
public function getAttribute(string $key): mixed
{
if (array_key_exists($key, $this->attributes)) {
return $this->attributes[$key];
Expand Down Expand Up @@ -101,7 +96,7 @@ public function getAttributes(): array
return $this->attributes;
}

public function setAttribute(string $key, $value): void
public function setAttribute(string $key, mixed $value): void
{
$this->attributes[$key] = $value;
}
Expand Down
15 changes: 5 additions & 10 deletions src/Node/NodeInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,14 @@ public function __toString(): string;

public function getName(): string;

/**
* @param string $key
*
* @return mixed
*/
public function getAttribute(string $key);
public function getAttribute(string $key): mixed;

/**
* @return mixed
* @return array<string, mixed>
*/
public function getAttributes();
public function getAttributes(): array;

public function setAttribute(string $key, $value): void;
public function setAttribute(string $key, mixed $value): void;

public function hasNode(string $key): bool;

Expand All @@ -39,5 +34,5 @@ public function addNode(NodeInterface $node): void;

public function replaceNode(NodeInterface $node): void;

public function removeNode(NodeInterface $node);
public function removeNode(NodeInterface $node): void;
}
2 changes: 1 addition & 1 deletion src/NodeTraverser/NodeTraverser.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class NodeTraverser
/**
* @var NodeVisitorInterface[]
*/
private $visitors = [];
private array $visitors = [];

public function addVisitor(NodeVisitorInterface $visitor): void
{
Expand Down
2 changes: 1 addition & 1 deletion src/NodeVisitor/AbstractNodeVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function enterNode(NodeInterface $node): ?NodeInterface
/**
* {@inheritdoc}
*/
public function leaveNode(NodeInterface $node)
public function leaveNode(NodeInterface $node): NodeInterface|NodeVisitorAction|null
{
return null;
}
Expand Down
7 changes: 1 addition & 6 deletions src/NodeVisitor/NodeVisitorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,5 @@ public function afterTraverse(NodeInterface $node): ?NodeInterface;

public function enterNode(NodeInterface $node): ?NodeInterface;

/**
* @param NodeInterface $node
*
* @return NodeInterface|NodeVisitorAction|null
*/
public function leaveNode(NodeInterface $node);
public function leaveNode(NodeInterface $node): NodeInterface|NodeVisitorAction|null;
}
3 changes: 3 additions & 0 deletions src/Renderer/RendererInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

use chrisjenkinson\StructuredDocumentParser\Visitor\VisitorInterface;

/**
* A visitor that produces output, such as HTML, from a node tree.
*/
interface RendererInterface extends VisitorInterface
{
}
Loading
Loading