Skip to content

Commit

Permalink
Merge pull request #5 from kellegous/dot-000
Browse files Browse the repository at this point in the history
Added DotRenderer for debugging of AutomataMatcher
  • Loading branch information
kellegous authored Oct 22, 2024
2 parents 158ce30 + ffe0f9d commit ed64c6e
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 3 deletions.
21 changes: 21 additions & 0 deletions bin/render-state-machine
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env php
<?php

declare(strict_types=1);

use Kellegous\CodeOwners\AutomataMatcher;
use Kellegous\CodeOwners\AutomataMatcher\DotRenderer;
use Kellegous\CodeOwners\Owners;

require __DIR__ . '/../vendor/autoload.php';

if ($argc !== 2) {
fprintf(STDERR, "Usage: %s <filename>\n", $argv[0]);
exit(1);
}

$matcher = AutomataMatcher::build(
Owners::fromFile($argv[1])->getRules()
);

printf("%s\n", DotRenderer::render($matcher));
30 changes: 28 additions & 2 deletions src/AutomataMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ private static function parsePattern(Pattern $pattern): array
$tokens = [];
$pattern = $pattern->toString();

$original = $pattern;

if (!str_starts_with($pattern, '/')) {
$pattern = '**/' . $pattern;
}
Expand Down Expand Up @@ -131,4 +129,32 @@ public function asJson(): array
{
return $this->start->jsonSerialize();
}

/**
* @return array{nodes: array<string, int>, edges: array{from: string, to: string, label: string}[]}
*/
public function getDebugInfo(): array
{
$patterns = [];
foreach ($this->rules as $rule) {
foreach (self::parsePattern($rule->getPattern()) as $token) {
$patterns[$token->getRegex()] = $token->getPattern();
}
}

$nodes = [];
$edges = [];
$this->start->getDebugInfo($nodes, $edges);
$edges = array_map(
function (array $edge) use ($patterns): array {
['from' => $from, 'to' => $to, 'label' => $label] = $edge;
if ($label !== '**') {
$label = $patterns[$label] ?? '??';
}
return ['from' => $from, 'to' => $to, 'label' => $label];
},
$edges
);
return ['nodes' => $nodes, 'edges' => $edges];
}
}
41 changes: 41 additions & 0 deletions src/AutomataMatcher/DotRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Kellegous\CodeOwners\AutomataMatcher;

use Kellegous\CodeOwners\AutomataMatcher;

final class DotRenderer
{
/**
* @param AutomataMatcher $matcher
* @return string
*/
public static function render(AutomataMatcher $matcher): string
{
['nodes' => $nodes, 'edges' => $edges] = $matcher->getDebugInfo();

$start = array_key_first($nodes);

$lines = [
'node [shape = circle; label = "";];',
"{$start} [peripheries = 2;];",
];
foreach ($nodes as $id => $priority) {
$label = $priority === -1 ? '' : $priority;
$lines[] = "{$id} [label=\"{$label}\";];";
}

foreach ($edges as ['from' => $from, 'to' => $to, 'label' => $label]) {
$lines[] = "{$from} -> {$to} [label=\"{$label}\"];";
}

return implode(
PHP_EOL,
[
'digraph G {',
...$lines,
'}',
]
);
}
}
35 changes: 34 additions & 1 deletion src/AutomataMatcher/State.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

namespace Kellegous\CodeOwners\AutomataMatcher;

use http\Exception\InvalidArgumentException;
use InvalidArgumentException;
use JsonSerializable;

final class State implements JsonSerializable
{
/**
* @var int
*/
private int $priority = -1;

/**
Expand All @@ -19,6 +22,9 @@ final class State implements JsonSerializable
*/
private bool $isRecursive;

/**
* @param bool $isRecursive
*/
public function __construct(bool $isRecursive = false)
{
$this->isRecursive = $isRecursive;
Expand Down Expand Up @@ -99,4 +105,31 @@ public function jsonSerialize(): array
'**' => $this->isRecursive,
];
}

/**
* @param array<string, int> $nodes
* @param array{from:int, to: int, label:string}[] $edges
* @return void
*/
public function getDebugInfo(
array &$nodes,
array &$edges
): void {
$nodes[spl_object_id($this)] = $this->priority;
foreach ($this->edges as $regex => $state) {
$edges[] = [
'from' => spl_object_id($this),
'to' => spl_object_id($state),
'label' => $regex,
];
$state->getDebugInfo($nodes, $edges);
}
if ($this->isRecursive) {
$edges[] = [
'from' => spl_object_id($this),
'to' => spl_object_id($this),
'label' => '**',
];
}
}
}

0 comments on commit ed64c6e

Please sign in to comment.