You are using a browser which doesn't fully support Cascading Style Sheets. This site will look much better in a browser that supports web standards, but its content is accessible to any browser or Internet device.
Parsing hooks
So based on your option and body declarations, the parser controls how it checks the tag syntax. If you need
further checks you can
hook into parsing by using the
hook
key, specifying a subroutine:
%tags=( EMPHASIZE => { # options options => TAGS_OPTIONAL, # perform special checks hook => sub { # get parameters my ( $tagline, $options, $body, $anchors )=@_; # checks $rc=... # reply results $rc; } }, COLORIZE => {...}, FONTIFY => {...}, ... );
Whenever the parser detects an occurence of the defined tag, it will invoke the hook function and pass the source line number, a reference to a hash of option name / value pairs to check, a reference to an array of body elements, and an anchor collection object. Using the option hash reference, the hook can read and modify the options. Different to this, the body array is a copy of the body part of the stream. Therefore the hook cannot modify the body part. (The parser depends on the body stream structure, and modifications could damage the streams integrity.)
Example
Here's an example hook from an implementation of
\IMAGE
. It checks if all necessary options were set and if a specified image file really exists (to warn a user when an invalid image file is detected). Finally, it modifies the source option to provide the absolute path to the backend, which is known when the source is parsed, but unknown when the backend processes the stream.
sub { # declare and init variable my $ok=PARSING_OK; # take parameters my ($tagLine, $options)=@_; # check them $ok=PARSING_FAILED, warn qq(\n\n[Error] Missing "src" option in IMAGE tag, line $tagLine.\n) unless exists $options->{src}; $ok=PARSING_ERROR, warn qq(\n\n[Error] Image file "$options->{src}" does not exist or is no file in IMAGE tag, line $tagLine.\n) if $ok==PARSING_OK and not (-e $options->{src} and not -d _); # absolutify the image source path (should work on UNIX and DOS, but other systems?) my ($base, $path, $type)=fileparse($options->{src}); $options->{src}=join('/', abs_path($path), basename($options->{src})) if $ok==PARSING_OK; # supply status $ok; },
Return codes
The hook in the last example replied
PARSING_OK
,
PARSING_ERROR
or
PARSING_FAILED
. In general, a hook should return one of the following codes (defined by
PerlPoint::Constants
):
return code | description |
---|---|
PARSING_COMPLETE
|
Parsing will be stopped immediately. The source is declared to be valid. |
PARSING_ERASE
|
The tag and all its contents will be removed from the stream. |
PARSING_ERROR
|
A semantic error occurred. This error will be counted, but parsing will be continued to possibly detect even more errors. |
PARSING_FAILED
|
A syntactic error occured. Parsing will be stopped immediately. |
PARSING_IGNORE
|
The parser will ignore the tag. The result is just the body (if any). |
PARSING_OK
|
The checked object is declared to be OK, parsing will be continued. |
Anchor management
But what about the anchor parameter? We did not speak about it yet. Well, the
anchor object passed to a hook is used "globally" to collect anchors declared in the
whole document. It is an instance of
PerlPoint::Anchors
, built and maintained by the parser (the class is part of the framework). Providing all tags access to this central object is an offer to tag designers to store
every anchor therein. By doing so all tags
referencing anchors can verify links quickly.
The next example shows an implementation of the basic tags
\SEQ
hook implementation.
\SEQ
can take an optional name, which declares the produced number to be referencable by that name. The hook checks the setting and adds a new anchor name to the anchor collection.
sub { # declare and init variable my $ok=PARSING_OK; # take parameters my ($tagLine, $options, $body, $anchors)=@_; # check them (a sequence type must be specified, a name is optional) $ok=PARSING_FAILED, warn qq(\n\n[Error] Missing "type" option in SEQ tag, line $tagLine.\n) unless exists $options->{type}; # still all right? if ($ok==PARSING_OK) { # get a new entry, store it by option $options->{__nr__}=++$seq{$options->{type}}; # if a name was set, store it together with the value $anchors->add($options->{name}, $seq{$options->{type}}) if $options->{name}; } # supply status $ok; },
Please note that when an anchor is registered, two values are stored. Besides the name of the anchor itself, this is a value which is something closely related to the anchor.
For \SEQ, the generated sequence number is made the anchors value. Whenever the anchor is accessed it will be possible to read the related number.
For pure link addresses it is recommended to store the anchor name both as name and value, but this depends on the usage which can be made of the link.
If one prefers, more anchor related things could be done in a hook, like checking if a new anchor is really new or was already declared before. That's up to you.
To sum it up, the parser managed anchor collection is a way to coordinate anchor related tags and make them interact
before backend invokation. The parser itself uses it to register every headline as a similarly named anchor. Anchor related basic tags like
\SEQ
and
\REF
use it as well. While there is no
convention to join their team, it is strongly
recommended to do so for a simple reason: PerlPoint document authors might be confused if several link checks are performed at parsing time, while other happen quite lately (in the backend). Nevertheless, the decision is yours.
Conclusion
Hooks are an interesting way to extend document parsing, but please take into consideration that tag hooks might be called quite often. So, if checks have to be performed, users will be glad if they are performed quickly.