目錄

名稱

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 串流。iteratorparser 都是必要的參數。如果未設定 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 本質上是一個基於串流的通訊協定,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::ObjectTAP::ParserTAP::Parser::IteratorTAP::Parser::Result