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")。
設定版本
$grammar->set_version(13);
告訴語法要支援哪個 TAP 語法版本。支援的最低版本為 12。雖然「TAP 版本」不是有效的版本 12 語法,但它會被接受,以便可以解析較高版本號碼。
標記化
my $token = $grammar->tokenize;
此方法會傳回一個 TAP::Parser::Result 物件,代表 TAP 的目前行。
標記類型
my @types = $grammar->token_types;
傳回此語法可以解析的不同標記類型。
語法
my $syntax = $grammar->syntax_for($token_type);
傳回一個預先編譯的正規表示式,它會比對與標記類型對應的 TAP 塊。例如(不要真的去注意這個,$grammar->syntax_for('comment')
會傳回 qr/^#(.*)/
)。
處理常式
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 本質上是一個基於串流的通訊協定,TAP::Parser 不使用正式語法。事實上,擁有無限串流是完全合法的。由於我們不會將正規表示式套用至串流,因此我們在此不使用正式語法。相反地,我們會逐行解析 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,