1TAP::Parser::Grammar(3pmP)erl Programmers Reference GuidTeAP::Parser::Grammar(3pm)
2
3
4
6 TAP::Parser::Grammar - A grammar for the Test Anything Protocol.
7
9 Version 3.17
10
12 use TAP::Parser::Grammar;
13 my $grammar = $self->make_grammar({
14 stream => $tap_parser_stream,
15 parser => $tap_parser,
16 version => 12,
17 });
18
19 my $result = $grammar->tokenize;
20
22 "TAP::Parser::Grammar" tokenizes lines from a TAP stream and constructs
23 TAP::Parser::Result subclasses to represent the tokens.
24
25 Do not attempt to use this class directly. It won't make sense. It's
26 mainly here to ensure that we will be able to have pluggable grammars
27 when TAP is expanded at some future date (plus, this stuff was really
28 cluttering the parser).
29
31 Class Methods
32 "new"
33
34 my $grammar = TAP::Parser::Grammar->new({
35 stream => $stream,
36 parser => $parser,
37 version => $version,
38 });
39
40 Returns TAP::Parser grammar object that will parse the specified
41 stream. Both "stream" and "parser" are required arguments. If
42 "version" is not set it defaults to 12 (see "set_version" for more
43 details).
44
45 Instance Methods
46 "set_version"
47
48 $grammar->set_version(13);
49
50 Tell the grammar which TAP syntax version to support. The lowest
51 supported version is 12. Although 'TAP version' isn't valid version 12
52 syntax it is accepted so that higher version numbers may be parsed.
53
54 "tokenize"
55
56 my $token = $grammar->tokenize;
57
58 This method will return a TAP::Parser::Result object representing the
59 current line of TAP.
60
61 "token_types"
62
63 my @types = $grammar->token_types;
64
65 Returns the different types of tokens which this grammar can parse.
66
67 "syntax_for"
68
69 my $syntax = $grammar->syntax_for($token_type);
70
71 Returns a pre-compiled regular expression which will match a chunk of
72 TAP corresponding to the token type. For example (not that you should
73 really pay attention to this, "$grammar->syntax_for('comment')" will
74 return "qr/^#(.*)/".
75
76 "handler_for"
77
78 my $handler = $grammar->handler_for($token_type);
79
80 Returns a code reference which, when passed an appropriate line of TAP,
81 returns the lexed token corresponding to that line. As a result, the
82 basic TAP parsing loop looks similar to the following:
83
84 my @tokens;
85 my $grammar = TAP::Grammar->new;
86 LINE: while ( defined( my $line = $parser->_next_chunk_of_tap ) ) {
87 foreach my $type ( $grammar->token_types ) {
88 my $syntax = $grammar->syntax_for($type);
89 if ( $line =~ $syntax ) {
90 my $handler = $grammar->handler_for($type);
91 push @tokens => $grammar->$handler($line);
92 next LINE;
93 }
94 }
95 push @tokens => $grammar->_make_unknown_token($line);
96 }
97
99 NOTE: This grammar is slightly out of date. There's still some
100 discussion about it and a new one will be provided when we have things
101 better defined.
102
103 The TAP::Parser does not use a formal grammar because TAP is
104 essentially a stream-based protocol. In fact, it's quite legal to have
105 an infinite stream. For the same reason that we don't apply regexes to
106 streams, we're not using a formal grammar here. Instead, we parse the
107 TAP in lines.
108
109 For purposes for forward compatability, any result which does not match
110 the following grammar is currently referred to as
111 TAP::Parser::Result::Unknown. It is not a parse error.
112
113 A formal grammar would look similar to the following:
114
115 (*
116 For the time being, I'm cheating on the EBNF by allowing
117 certain terms to be defined by POSIX character classes by
118 using the following syntax:
119
120 digit ::= [:digit:]
121
122 As far as I am aware, that's not valid EBNF. Sue me. I
123 didn't know how to write "char" otherwise (Unicode issues).
124 Suggestions welcome.
125 *)
126
127 tap ::= version? { comment | unknown } leading_plan lines
128 |
129 lines trailing_plan {comment}
130
131 version ::= 'TAP version ' positiveInteger {positiveInteger} "\n"
132
133 leading_plan ::= plan skip_directive? "\n"
134
135 trailing_plan ::= plan "\n"
136
137 plan ::= '1..' nonNegativeInteger
138
139 lines ::= line {line}
140
141 line ::= (comment | test | unknown | bailout ) "\n"
142
143 test ::= status positiveInteger? description? directive?
144
145 status ::= 'not '? 'ok '
146
147 description ::= (character - (digit | '#')) {character - '#'}
148
149 directive ::= todo_directive | skip_directive
150
151 todo_directive ::= hash_mark 'TODO' ' ' {character}
152
153 skip_directive ::= hash_mark 'SKIP' ' ' {character}
154
155 comment ::= hash_mark {character}
156
157 hash_mark ::= '#' {' '}
158
159 bailout ::= 'Bail out!' {character}
160
161 unknown ::= { (character - "\n") }
162
163 (* POSIX character classes and other terminals *)
164
165 digit ::= [:digit:]
166 character ::= ([:print:] - "\n")
167 positiveInteger ::= ( digit - '0' ) {digit}
168 nonNegativeInteger ::= digit {digit}
169
171 Please see "SUBCLASSING" in TAP::Parser for a subclassing overview.
172
173 If you really want to subclass TAP::Parser's grammar the best thing to
174 do is read through the code. There's no easy way of summarizing it
175 here.
176
178 TAP::Object, TAP::Parser, TAP::Parser::Iterator, TAP::Parser::Result,
179
180
181
182perl v5.12.4 2011-06-07 TAP::Parser::Grammar(3pm)