Skip to content

Commit

Permalink
Support templates
Browse files Browse the repository at this point in the history
  • Loading branch information
james-cnz committed Feb 28, 2024
1 parent bcd8386 commit 4ad34bc
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 15 deletions.
28 changes: 20 additions & 8 deletions classes/type_parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ class type_parser {
/** @var bool when we encounter an unknown type, should we go wide or narrow */
protected $gowide = false;

/** @var array<string, string> type templates */
protected $templates = [];

/** @var object{startpos: non-negative-int, endpos: non-negative-int, text: ?non-empty-string}[] next tokens */
protected $nexts = [];

Expand All @@ -149,26 +152,34 @@ class type_parser {

/**
* Constructor
* @param array<non-empty-string, non-empty-string> $usealiases aliases are keys, class names are values
* @param array<non-empty-string, object{extends: ?non-empty-string, implements: non-empty-string[]}> $artifacts inherit tree
* @param \local_moodlecheck_file $file
*/
public function __construct(array $usealiases = [], array $artifacts = []) {
$this->usealiases = $usealiases;
$this->artifacts = $artifacts;
public function __construct(\local_moodlecheck_file $file) {
$this->usealiases = $file->get_use_aliases();
$this->artifacts = $file->get_artifacts_flat();
}

/**
* Parse a type and possibly variable name
*
* @param ?\local_moodlecheck_phpdocs $phpdocs
* @param string $text the text to parse
* @param 0|1|2|3 $getwhat what to get 0=type only 1=also var 2=also modifiers (& ...) 3=also default
* @param bool $gowide if we can't determine the type, should we assume wide (for native type) or narrow (for PHPDoc)?
* @return array{?non-empty-string, ?non-empty-string, string, bool} the simplified type, variable, remaining text,
* and whether the type is explicitly nullable
*/
public function parse_type_and_var(string $text, int $getwhat, bool $gowide): array {
public function parse_type_and_var(?\local_moodlecheck_phpdocs $phpdocs,
string $text, int $getwhat, bool $gowide): array {

// Initialise variables.
if ($phpdocs) {
$artifact = $phpdocs->get_artifact();
$artifacttemplates = ($artifact && $artifact->phpdocs) ? $artifact->phpdocs->get_templates() : [];
$this->templates = array_merge($artifacttemplates, $phpdocs->get_templates());
} else {
$this->templates = [];
}
$this->text = strtolower($text);
$this->textwithcase = $text;
$this->gowide = $gowide;
Expand Down Expand Up @@ -944,7 +955,9 @@ protected function parse_basic_type(): string {
}
$type = ucfirst($type);
assert($type != '');
if ($this->next == '<') {
if ($this->templates[strtolower($type)] ?? null) {
$type = $this->templates[strtolower($type)];
} else if ($this->next == '<') {
// Collection / Traversable.
$this->parse_token('<');
$firsttype = $this->parse_any_type();
Expand Down Expand Up @@ -978,7 +991,6 @@ protected function parse_basic_type(): string {
$type = $this->gowide ? 'mixed' : 'never';
}

assert(strpos($type, '|') === false && strpos($type, '&') === false);
return $type;
}

Expand Down
45 changes: 39 additions & 6 deletions file.php
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ public function &get_classes() {
*/
public function get_type_parser() {
if (!$this->typeparser) {
$this->typeparser = new \local_moodlecheck\type_parser($this->get_use_aliases(), $this->get_artifacts_flat());
$this->typeparser = new \local_moodlecheck\type_parser($this);
}
return $this->typeparser;
}
Expand Down Expand Up @@ -517,13 +517,13 @@ public function &get_functions() {
$text .= $argtokens[$j][1];
}
}
list($type, $variable, $default, $nullable) = $typeparser->parse_type_and_var($text, 3, true);
list($type, $variable, $default, $nullable) = $typeparser->parse_type_and_var(null, $text, 3, true);

$function->arguments[] = [$type, $variable, $nullable];
}

// Get return type.
$returnpair = $this->find_tag_pair($argumentspair[1] + 1, ':', '{', ['{', ';']);
$returnpair = $this->find_tag_pair($argumentspair ? $argumentspair[1] + 1 : $tid + 1, ':', '{', ['{', ';']);
if ($returnpair !== false && $returnpair[1] - $returnpair[0] > 1) {
$rettokens =
array_slice($tokens, $returnpair[0] + 1, $returnpair[1] - $returnpair[0] - 1);
Expand All @@ -536,7 +536,7 @@ public function &get_functions() {
$text .= $rettokens[$j][1];
}
}
list($type, $varname, $default, $nullable) = $typeparser->parse_type_and_var($text, 0, true);
list($type, $varname, $default, $nullable) = $typeparser->parse_type_and_var(null, $text, 0, true);

$function->return = $type;

Expand Down Expand Up @@ -586,7 +586,7 @@ public function &get_variables() {
$text .= $this->tokens[$typetid][1];
}
}
list($type, $varname, $default, $nullable) = $typeparser->parse_type_and_var($text, 1, true);
list($type, $varname, $default, $nullable) = $typeparser->parse_type_and_var(null, $text, 1, true);
$variable->type = $type;
} else {
$variable->type = null;
Expand Down Expand Up @@ -1237,6 +1237,7 @@ class local_moodlecheck_phpdocs {
'static',
'staticvar',
'subpackage',
// 'template',
'throws',
'todo',
'tutorial',
Expand Down Expand Up @@ -1283,6 +1284,7 @@ class local_moodlecheck_phpdocs {
'see',
'since',
'subpackage',
// 'template',
'throws',
'todo',
'uses',
Expand Down Expand Up @@ -1378,6 +1380,10 @@ public function __construct($file, $token, $tid) {
$this->description = trim($this->description);
}

public function get_artifact() {
return $this->file->is_inside_artifact($this->originaltid);
}

/**
* Returns all tags found in phpdocs
*
Expand Down Expand Up @@ -1475,6 +1481,32 @@ public function get_shortdescription() {
}
}

public function get_templates() {
$typeparser = $this->file->get_type_parser();
$templates = [];

foreach ($this->get_tags('template') as $token) {
$token = trim($token);
$nameend = 0;
while ($nameend < strlen($token) && (ctype_alnum($token[$nameend]) || $token[$nameend] == '_')) {
$nameend++;
}
if ($nameend > 0) {
$ofstart = $nameend;
while ($ofstart < strlen($token) && ctype_space($token[$ofstart])) {
$ofstart++;
}
$type = 'mixed';
if (substr($token, $ofstart, 2) == 'of') {
list($type) = $typeparser->parse_type_and_var(null, substr($token, $ofstart+2), 0, false);
}
$templates[strtolower(substr($token, 0, $nameend))] = $type;
}
}

return $templates;
}

/**
* Returns list of parsed param tokens found in phpdocs
*
Expand All @@ -1489,7 +1521,8 @@ public function get_params(string $tag, int $getwhat) {
$params = [];

foreach ($this->get_tags($tag) as $token) {
list($type, $variable, $description) = $typeparser->parse_type_and_var($token, $getwhat, false);
list($type, $variable, $description) =
$typeparser->parse_type_and_var($this, $token, $getwhat, false);
$param = [];
$param[] = $type;
if ($getwhat >= 1) {
Expand Down
2 changes: 1 addition & 1 deletion rules/phpdocs_basic.php
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ function local_moodlecheck_functionarguments(local_moodlecheck_file $file) {
*/
function local_moodlecheck_normalise_function_type(string $typelist): ?string {
$typeparser = new \local_moodlecheck\type_parser();
list($type, $variable, $remainder) = $typeparser->parse_type_and_var($typelist, 0, true);
list($type, $variable, $remainder) = $typeparser->parse_type_and_var(null, $typelist, 0, true);
return $type;
}

Expand Down

0 comments on commit 4ad34bc

Please sign in to comment.