TAP::Parser::Grammar - Test Anything Protocol 的语法。
版本 3.44
use TAP::Parser::Grammar;
my $grammar = $self->make_grammar({
iterator => $tap_parser_iterator,
parser => $tap_parser,
version => 12,
});
my $result = $grammar->tokenize;
TAP::Parser::Grammar
将来自 TAP::Parser::Iterator 的行进行标记化,并构建 TAP::Parser::Result 子类来表示标记。
不要尝试直接使用此类。它没有意义。它主要存在是为了确保当 TAP 在未来某个时间扩展时,我们能够拥有可插拔的语法(此外,这些东西真的会使解析器混乱)。
new
my $grammar = TAP::Parser::Grammar->new({
iterator => $iterator,
parser => $parser,
version => $version,
});
返回 TAP::Parser 语法对象,它将解析来自指定迭代器的 TAP 流。iterator
和 parser
是必需的参数。如果未设置 version
,则默认为 12
(有关更多详细信息,请参见 "set_version")。
set_version
$grammar->set_version(13);
告诉语法要支持哪个 TAP 语法版本。最低支持版本为 12。虽然“TAP 版本”不是有效的版本 12 语法,但它被接受,以便可以解析更高的版本号。
tokenize
my $token = $grammar->tokenize;
此方法将返回一个 TAP::Parser::Result 对象,表示当前行的 TAP。
token_types
my @types = $grammar->token_types;
返回此语法可以解析的不同类型的标记。
syntax_for
my $syntax = $grammar->syntax_for($token_type);
返回一个预编译的正则表达式,它将匹配与标记类型相对应的 TAP 块。例如(不是说你应该真正关注这一点,$grammar->syntax_for('comment')
将返回 qr/^#(.*)/
。
handler_for
my $handler = $grammar->handler_for($token_type);
返回一个代码引用,当传递给它一个适当的 TAP 行时,它将返回与该行相对应的词法分析标记。因此,基本的 TAP 解析循环看起来类似于以下内容
my @tokens;
my $grammar = TAP::Grammar->new;
LINE: while ( defined( my $line = $parser->_next_chunk_of_tap ) ) {
for my $type ( $grammar->token_types ) {
my $syntax = $grammar->syntax_for($type);
if ( $line =~ $syntax ) {
my $handler = $grammar->handler_for($type);
push @tokens => $grammar->$handler($line);
next LINE;
}
}
push @tokens => $grammar->_make_unknown_token($line);
}
注意:此语法略微过时。关于它仍然有一些讨论,当我们更好地定义事物时,将提供一个新的语法。
TAP::Parser 不使用正式语法,因为 TAP 本质上是一个基于流的协议。事实上,拥有一个无限流是完全合法的。由于我们不将正则表达式应用于流,因此我们在这里不使用正式语法。相反,我们按行解析 TAP。
为了向前兼容,任何不匹配以下语法的结果目前被称为 TAP::Parser::Result::Unknown。它不是解析错误。
正式语法将类似于以下内容
(*
For the time being, I'm cheating on the EBNF by allowing
certain terms to be defined by POSIX character classes by
using the following syntax:
digit ::= [:digit:]
As far as I am aware, that's not valid EBNF. Sue me. I
didn't know how to write "char" otherwise (Unicode issues).
Suggestions welcome.
*)
tap ::= version? { comment | unknown } leading_plan lines
|
lines trailing_plan {comment}
version ::= 'TAP version ' positiveInteger {positiveInteger} "\n"
leading_plan ::= plan skip_directive? "\n"
trailing_plan ::= plan "\n"
plan ::= '1..' nonNegativeInteger
lines ::= line {line}
line ::= (comment | test | unknown | bailout ) "\n"
test ::= status positiveInteger? description? directive?
status ::= 'not '? 'ok '
description ::= (character - (digit | '#')) {character - '#'}
directive ::= todo_directive | skip_directive
todo_directive ::= hash_mark 'TODO' ' ' {character}
skip_directive ::= hash_mark 'SKIP' ' ' {character}
comment ::= hash_mark {character}
hash_mark ::= '#' {' '}
bailout ::= 'Bail out!' {character}
unknown ::= { (character - "\n") }
(* POSIX character classes and other terminals *)
digit ::= [:digit:]
character ::= ([:print:] - "\n")
positiveInteger ::= ( digit - '0' ) {digit}
nonNegativeInteger ::= digit {digit}
请参阅 "子类化" 在 TAP::Parser 中 以获取子类化概述。
如果你真的想子类化 TAP::Parser 的语法,最好的方法是阅读代码。这里没有简单的方法来总结它。
TAP::Object,TAP::Parser,TAP::Parser::Iterator,TAP::Parser::Result,