The "tolerant" analysis mode allows parsing a type grammar embedded in other arbitrary data, without requiring the full input to be a valid type statement.
This is convenient, for example, for analyzing phpdoc (docblocks): a @return annotation contains a type declaration followed by a free-text description, and there is no delimiter between the two other than "the type grammar stops making sense here".
Unlike parse(), which either returns a fully valid TypeNode or throws, TypeParser::parseTolerant() always returns a TypeLang\Parser\ParsedResult object:
final readonly class ParsedResult
{
public TypeNode $type;
/**
* Last processed token offset, in bytes.
*/
public int $offset;
}
Basic Usage
use TypeLang\Parser\TypeParser;
$parser = new TypeParser();
$result = $parser->parseTolerant('int and more text');
var_dump($result->type->name->toString()); // string(3) "int"
var_dump($result->offset); // int(4)
$result->offset points right after the last byte that was actually consumed while building $result->type — including any trailing whitespace that belongs to it. Everything from that offset onward is simply whatever was left in the source:
$remainder = substr('int and more text', $result->offset);
var_dump($remainder); // string(13) "and more text"
Parsing a Docblock Annotation
Let's parse the contents of a " @return " docblock. The same technique applies to any other annotation that embeds a type followed by free text.
$parser = new TypeParser();
$content = <<<'PHP'
@return Example<T> Returns something very interesting!
PHP;
// There is no need to strip the description ourselves,
// only the tag name:
$content = substr($content, strlen('@return '));
// "Example<T> Returns something very interesting!"
$result = $parser->parseTolerant($content);
var_dump($result->type);
Tolerant mode does not attempt to repair broken syntax — it stops at the last point where a complete sub-rule was matched and treats everything past it as trailing content, however implausible that trailing content looks.
Here the unterminated { of the shape-fields list is never entered, so the parser falls back to the last valid statement — the bare array named type — and reports offset 5, right before the {.