TAP::P...rammar(3perl)

🌸 TAP::Parser::Grammar 🌸

hi bestie!! πŸ’– welcome to the TAP::Parser::Grammar(3perl) page from the Perl Programmers Reference Guide. lowkey this one is parser-internals core, and it's giving "I'm the engine room, don't touch me unless you know what you're doing" energy. but don't worry β€” I got you, we're walking through the whole thing together. grab a snack πŸ“ and let's gooo.


✨ NAME ✨

TAP::Parser::Grammar β€” a grammar for the Test Anything Protocol. periodt. πŸ‘‘

πŸŽ€ VERSION πŸŽ€

Version 3.52 ✨

πŸ¦‹ SYNOPSIS πŸ¦‹

  use TAP::Parser::Grammar;
  my $grammar = $self->make_grammar({
    iterator => $tap_parser_iterator,
    parser   => $tap_parser,
    version  => 12,
  });

  my $result = $grammar->tokenize;

see how cute and tiny that is?? that's the whole vibe check. πŸ’…

πŸ’œ DESCRIPTION πŸ’œ

okay so TAP::Parser::Grammar tokenizes the lines coming out of a TAP::Parser::Iterator, and it builds TAP::Parser::Result subclasses to represent those tokens. that's the job. that's the whole job. 🫢

bestie, listen: do not try to use this class directly. it won't make sense. I'm serious. it's mainly here so that someday, when TAP gets expanded at some future date, we'll be able to have pluggable grammars β€” and also because honestly this stuff was really cluttering up the parser. πŸ’€

πŸ”₯ METHODS πŸ”₯

πŸ‘‘ Class Methods

  • new
  my $grammar = TAP::Parser::Grammar->new({
      iterator => $iterator,
      parser   => $parser,
      version  => $version,
  });

Returns a TAP::Parser grammar object that will parse the TAP stream from the iterator you specified. both iterator and parser are required arguments, no skipping them πŸ™ˆ. if version isn't set, it just defaults to 12 β€” peep set_version if you wanna know more.

🧚 Instance Methods

  • set_version
  $grammar->set_version(13);

Tells the grammar which TAP syntax version to support. the lowest supported version is 12. and like, technically 'TAP version' isn't valid version 12 syntax, but it is accepted anyway so that higher version numbers can get parsed. iconic behavior honestly ✨

  • tokenize
  my $token = $grammar->tokenize;

This method returns a TAP::Parser::Result object representing the current line of TAP. that's it. that's the tea. 🍡

  • token_types
  my @types = $grammar->token_types;

Returns the different types of tokens which this grammar can parse. iykyk.

  • syntax_for
  my $syntax = $grammar->syntax_for($token_type);

Returns a pre-compiled regular expression which will match a chunk of TAP corresponding to that token type. for example (not that you should really be paying attention to this, but) $grammar->syntax_for('comment') will return qr/^#(.*)/. slay πŸŽ€

  • handler_for
  my $handler = $grammar->handler_for($token_type);

Returns a code reference which, when you pass it an appropriate line of TAP, returns the lexed token corresponding to that line. as a result, the basic TAP parsing loop looks similar to the following:

  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);
  }

like hello?? that loop ate and left no crumbs πŸ”₯

🌈 TAP GRAMMAR 🌈

NOTE: This grammar is slightly out of date. There's still some discussion about it and a new one will be provided when we have things better defined. πŸ™ˆ

The TAP::Parser does not use a formal grammar, because TAP is essentially a stream-based protocol. in fact, it's quite legal to have an infinite stream. and for the very same reason that we don't apply regexes to streams, we're not using a formal grammar here either. instead, we parse the TAP in lines. simple as that. πŸ’«

For purposes of forward compatibility, any result which does not match the following grammar is currently referred to as TAP::Parser::Result::Unknown. it is not a parse error. okay?? no panicking. 😌

A formal grammar would look similar to the following:

  (*
      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}

(the original author literally said "Sue me." and honestly? respect. πŸ’€πŸ‘‘)

🧚 SUBCLASSING 🧚

Please see "SUBCLASSING" in TAP::Parser for the subclassing overview, bestie.

and if you really want to subclass TAP::Parser's grammar, the best thing you can possibly do is read through the code. there's genuinely no easy way to summarize it here. no shortcuts, no vibes-only path, you just gotta read it. 😭

⭐ SEE ALSO ⭐

TAP::Object, TAP::Parser, TAP::Parser::Iterator, TAP::Parser::Result,


and that's the whole page, bestie!! 🫢 this was TAP::Parser::Grammar, perl v5.44.0, dated 2026-10-17 β€” go forth and tokenize responsibly, and remember: do not use this class directly. I'm not asking, I'm telling. πŸ’…βœ¨ mwah! 🌸

πŸ“¦ where this page comes from
  • arch rolling: perl 5.44.0-1 Β· Artistic-1.0-Perl AND GPL-1.0-or-later
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms