351 lines
14 KiB
Plaintext
351 lines
14 KiB
Plaintext
NAME
|
|
|
|
XS::Parse::Sublike - XS functions to assist in parsing sub-like syntax
|
|
|
|
DESCRIPTION
|
|
|
|
This module provides some XS functions to assist in writing parsers for
|
|
sub-like syntax, primarily for authors of keyword plugins using the
|
|
PL_keyword_plugin hook mechanism. It is unlikely to be of much use to
|
|
anyone else; and highly unlikely to be any use when writing perl code
|
|
using these. Unless you are writing a keyword plugin using XS, this
|
|
module is not for you.
|
|
|
|
This module is also currently experimental, and the design is still
|
|
evolving and subject to change. Later versions may break ABI
|
|
compatibility, requiring changes or at least a rebuild of any module
|
|
that depends on it.
|
|
|
|
XS FUNCTIONS
|
|
|
|
boot_xs_parse_sublike
|
|
|
|
void boot_xs_parse_sublike(double ver)
|
|
|
|
Call this function from your BOOT section in order to initialise the
|
|
module and parsing hooks.
|
|
|
|
ver should either be 0 or a decimal number for the module version
|
|
requirement; e.g.
|
|
|
|
boot_xs_parse_sublike(0.04);
|
|
|
|
xs_parse_sublike
|
|
|
|
int xs_parse_sublike(const struct XSParseSublikeHooks *hooks, void *hookdata, OP **op_ptr)
|
|
|
|
This function performs the actual parsing of a sub-like keyword. It
|
|
expects the lexer to be at a position just after the introduction
|
|
keyword has been consumed, and will proceed to parse an optional name,
|
|
list of attributes, signature (if enabled by use feature 'signatures'),
|
|
and code body. The return value and op_ptr can be used directly from
|
|
the keyword plugin function. It is intended this function be invoked
|
|
from it, and the result returned directly.
|
|
|
|
For a more automated handling of keywords, see
|
|
"register_xs_parse_sublike".
|
|
|
|
hooks should be a structure that can provide optional function pointers
|
|
used to customise the parsing process at various stages. hookdata is an
|
|
opaque pointer which is passed through to each of the hook stage
|
|
functions.
|
|
|
|
register_xs_parse_sublike
|
|
|
|
void register_xs_parse_sublike(const char *keyword,
|
|
const struct XSParseSublikeHooks *hooks, void *hookdata)
|
|
|
|
This function installs a set of parsing hooks to be associated with the
|
|
given keyword. Such a keyword will then be handled automatically by a
|
|
keyword parser installed by XS::Parse::Sublike itself.
|
|
|
|
When the keyword is encountered, the hook's permit function is first
|
|
tested to see if the keyword is permitted at this point. If the
|
|
function returns true then the keyword is consumed and parsed as per
|
|
"xs_parse_sublike".
|
|
|
|
hookdata is an opaque pointer which is passed through to each of the
|
|
hook stage functions when they are invoked.
|
|
|
|
xs_parse_sublike_any
|
|
|
|
int xs_parse_sublike_any(const struct XSParseSublikeHooks *hooks, void *hookdata,
|
|
OP **op_ptr)
|
|
|
|
This function expects to consume an introduction keyword at the lexer
|
|
position which is either sub or the name of another sub-like keyword,
|
|
which has been previously registered using "register_xs_parse_sublike".
|
|
It then proceeds to parse the subsequent syntax similar to how it would
|
|
have parsed if encountered by the module's own keyword parser plugin,
|
|
except that the second set of hooks given here also take effect.
|
|
|
|
If a regular sub is encountered, then this is parsed using the hooks in
|
|
a similar way to xs_parse_sublike().
|
|
|
|
If a different registered sub-like keyword is encountered, then parsing
|
|
is performed using both sets of hooks - the ones given to this function
|
|
as well as the ones registered with the keyword. This allows their
|
|
effects to combined. The hooks given by the hooks argument are
|
|
considered to be on the "outside" from those of the registered keyword
|
|
"inside". The outside ones run first for all stages, except
|
|
pre_blockend which runs them inside-out.
|
|
|
|
hookdata is an opaque pointer which is passed through to each of the
|
|
hook stage functions when they are invoked.
|
|
|
|
Note that this function is now vaguely discouraged, in favour of using
|
|
a prefixing keyword instead, by using the XS_PARSE_SUBLIKE_FLAG_PREFIX
|
|
flag.
|
|
|
|
PARSE CONTEXT
|
|
|
|
The various hook stages all share state about the ongoing parse process
|
|
using various fields of the XSParseSublikeContext structure.
|
|
|
|
struct XSParseSublikeContext {
|
|
SV *name;
|
|
OP *attrs;
|
|
OP *body;
|
|
CV *cv;
|
|
U32 actions;
|
|
HV *moddata;
|
|
}
|
|
|
|
The actions field will contain a bitmask of action flags that control
|
|
the various steps that XS::Parse::Sublike might take inbetween invoking
|
|
hook stages. The initial value of this field is set after the
|
|
name-parsing stage, depending on whether or not a name is found. Stage
|
|
hook functions may modify the field to adjust the subsequent behaviour.
|
|
|
|
At the current ABI version, a module will have to set the
|
|
XS_PARSE_SUBLIKE_COMPAT_FLAG_DYNAMIC_ACTIONS bit of the flags field in
|
|
order to make use of the actions field. A future ABI version may remove
|
|
this restriction.
|
|
|
|
XS_PARSE_SUBLIKE_ACTION_CVf_ANON
|
|
|
|
If set, the start_subparse() call will be set up for an anonymous
|
|
function protosub; if not it will be set for a named function. This
|
|
is set by default if a name was not found.
|
|
|
|
XS_PARSE_SUBLIKE_ACTION_SET_CVNAME
|
|
|
|
If set, the newly-constructed CV will have the given name set on it.
|
|
This is set by default if a name was found.
|
|
|
|
On Perl versions 5.22 and above, this flag can be set even if
|
|
XS_PARSE_SUBLIKE_ACTION_INSTALL_SYMBOL is not. In this case, the CV
|
|
will not be reachable via the symbol table, even though it knows its
|
|
own name and pretends that it is. On earlier versions of perl this
|
|
flag will be ignored in that case.
|
|
|
|
XS_PARSE_SUBLIKE_ACTION_INSTALL_SYMBOL
|
|
|
|
If set, the newly-constructed CV will be installed into the symbol
|
|
table at its given name. Note that it is not possible to enable this
|
|
flag without also enabling XS_PARSE_SUBLIKE_ACTION_SET_CVNAME. This
|
|
is set by default if a name was found.
|
|
|
|
XS_PARSE_SUBLIKE_ACTION_REFGEN_ANONCODE
|
|
|
|
If set, the syntax will yield the OP_REFGEN / OP_ANONCODE optree
|
|
fragment typical of anonymous code expressions; if not it will be
|
|
OP_NULL. This is set by default if a name was not found.
|
|
|
|
XS_PARSE_SUBLIKE_ACTION_RET_EXPR
|
|
|
|
If set, the syntax will parse like an expression; if not it will
|
|
parse like a statement. This is set by default if a name was not
|
|
found.
|
|
|
|
The moddata field will point towards an HV that modules can used to
|
|
store extra data between stages. As a naming convention a module should
|
|
prefix its keys with its own module name and a slash character,
|
|
"Some::Module/field". The field will point to a newly-created HV for
|
|
every parse invocation, and will be released when each parse is
|
|
complete.
|
|
|
|
PARSE HOOKS
|
|
|
|
The XSParseSublikeHooks structure provides the following hook stages,
|
|
which are invoked in the given order.
|
|
|
|
The structure has a flags field, which controls various optional parts
|
|
of operation. The following flags are defined.
|
|
|
|
XS_PARSE_SUBLIKE_FLAG_FILTERATTRS
|
|
|
|
If set, the optional filter_attr stage will be invoked.
|
|
|
|
XS_PARSE_SUBLIKE_FLAG_BODY_OPTIONAL
|
|
|
|
If not set, the require_parts field will imply the
|
|
XS_PARSE_SUBLIKE_PART_BODY flag, making the body part required. By
|
|
setting this flag this will no longer happen. If all hooks agree,
|
|
then the body will become optional.
|
|
|
|
XS_PARSE_SUBLIKE_FLAG_PREFIX
|
|
|
|
If set, the keyword is considered to be a prefix that can be placed
|
|
in front of sub or another sub-like keyword, to add its set of hooks
|
|
in addition to those of the following keyword. These prefices may be
|
|
further stacked.
|
|
|
|
In addition there are two U8 fields named require_parts and skip_parts
|
|
which control the behaviour of various parts of the syntax which are
|
|
usually optional. Any parts with bits set in require_parts become
|
|
non-optional, and an error if they are missing. Any parts with bits set
|
|
in skip_parts will skip the relevant part of the parsing process.
|
|
|
|
When multiple sets of hooks are combined by the xs_parse_sublike_any
|
|
function, or as part of parsing prefixing keywords, these bitmasks are
|
|
accumulated together with inclusive or. Any part required by any set of
|
|
hooks will still be required; any step skipped by either will be
|
|
skipped entirely.
|
|
|
|
If the same bit is set in both fields then the relevant parsing step
|
|
will not be performed but it will still be an error for that section to
|
|
be missing. This is likely not useful.
|
|
|
|
Note that for skipped parts, only the actual parsing steps are skipped.
|
|
A hook function can still set the relevant fields in the context
|
|
structure anyway to force a particular value for those parts.
|
|
|
|
XS_PARSE_SUBLIKE_PART_NAME
|
|
|
|
The name of the function.
|
|
|
|
XS_PARSE_SUBLIKE_PART_ATTRS
|
|
|
|
The attributes of the function.
|
|
|
|
This part can be skipped, but the bit is ignored when in
|
|
require_parts. It is always permitted to not provide any additional
|
|
attributes to a function definition.
|
|
|
|
XS_PARSE_SUBLIKE_PART_SIGNATURE
|
|
|
|
The parameter signature of the function.
|
|
|
|
This part can be skipped, but it is always permitted not to provide a
|
|
signature for a function definition even if the bit it set in
|
|
require_parts. This is because such syntax only applies when use
|
|
feature 'signatures' is in effect, and only on supporting perl
|
|
versions.
|
|
|
|
However, setting the bit in require_parts instead has the effect of
|
|
enabling use feature 'signatures' (at least on supporting perl
|
|
versions), thus permitting the syntax to use a signature even if the
|
|
signatures feature was not previously enabled.
|
|
|
|
XS_PARSE_SUBLIKE_PART_BODY
|
|
|
|
The actual body of the function, expressed as a brace-delimited
|
|
block.
|
|
|
|
This part cannot be skipped, but it can be made optional by omitting
|
|
it from the require_parts field. Instead of the block, it is
|
|
permitted to place a single semicolon (;) to act as a statement
|
|
terminator; thus giving the same syntax as a subroutine forward
|
|
declaration.
|
|
|
|
In this case, the body and cv fields of the context structure will
|
|
remain NULL.
|
|
|
|
This flag is currently implied on the require_parts field if the hook
|
|
does not supply the XS_PARSE_SUBLIKE_FLAG_BODY_OPTIONAL flag; meaning
|
|
that most use-cases will make it a required part.
|
|
|
|
The permit Stage
|
|
|
|
const char *permit_hintkey
|
|
bool (*permit)(pTHX_ void *hookdata)
|
|
|
|
Called by the installed keyword parser hook which is used to handle
|
|
keywords registered by "register_xs_parse_sublike".
|
|
|
|
As a shortcut for the common case, the permit_hintkey may point to a
|
|
string to look up from the hints hash. If the given key name is not
|
|
found in the hints hash then the keyword is not permitted. If the key
|
|
is present then the permit function is invoked as normal.
|
|
|
|
If not rejected by a hint key that was not found in the hints hash, the
|
|
function part of the stage is called next and should inspect whether
|
|
the keyword is permitted at this time perhaps by inspecting other
|
|
lexical clues, and return true only if the keyword is permitted.
|
|
|
|
Both the string and the function are optional. Either or both may be
|
|
present. If neither is present then the keyword is always permitted -
|
|
which is likely not what you wanted to do.
|
|
|
|
Parse Name
|
|
|
|
At this point, the optional name is parsed and filled into the name
|
|
field of the context.
|
|
|
|
The pre_subparse Stage
|
|
|
|
void (*pre_subparse)(pTHX_ struct XSParseSublikeContext *ctx, void *hookdata)
|
|
|
|
Invoked just before start_subparse() is called.
|
|
|
|
Parse Attrs
|
|
|
|
At this point the optional sub attributes are parsed and filled into
|
|
the attrs field of the context, then block_start() is called.
|
|
|
|
The optional filter_attr Stage
|
|
|
|
bool (*filter_attr)(pTHX_ struct XSParseSublikeContext *ctx,
|
|
SV *attr, SV *val, void *hookdata);
|
|
|
|
If the flags field includes XS_PARSE_SUBLIKE_FLAG_FILTERATTRS then each
|
|
individual attribute is passed through this optional filter function
|
|
immediately as each is parsed. attr will be a string SV containing the
|
|
name of the attribute, and val will either be NULL, or a string SV
|
|
containing the contents of the parens after its name (without the
|
|
parens themselves).
|
|
|
|
If the filter returns true, it indicates that it has in some way
|
|
handled the attribute and it should not be added to the list given to
|
|
newATTRSUB(). If the filter returns false it will be handled in the
|
|
usual way; equivalent to the case where the filter function did not
|
|
exist.
|
|
|
|
The post_blockstart Stage
|
|
|
|
void (*post_blockstart)(pTHX_ struct XSParseSublikeContext *ctx, void *hookdata)
|
|
|
|
Invoked after the block_start() function has been called. This hook
|
|
stage may wish to perform any alterations of PL_compcv or related,
|
|
inspect or alter the lexical pad, provide hints hash values, or any
|
|
other tasks before the signature and code body are parsed.
|
|
|
|
Parse Body
|
|
|
|
At this point, the main body of the function is parsed and the optree
|
|
is stored in the body field of the context. If the perl version
|
|
supports sub signatures and they are enabled and found, the body will
|
|
be prefixed with the signature ops as well.
|
|
|
|
The pre_blockend Stage
|
|
|
|
void (*pre_blockend)(pTHX_ struct XSParseSublikeContext *ctx, void *hookdata)
|
|
|
|
Invoked just before the block_end() function is invoked. The hook stage
|
|
may wish to inspect or alter the optree stored in the body context
|
|
field.
|
|
|
|
The post_newcv Stage
|
|
|
|
void (*post_newcv)(pTHX_ struct XSParseSublikeContext *ctx, void *hookdata)
|
|
|
|
Invoked just after newATTRSUB() has been invoked on the optree. The
|
|
hook stage may wish to inspect or alter the CV stored in the cv context
|
|
field.
|
|
|
|
AUTHOR
|
|
|
|
Paul Evans <leonerd@leonerd.org.uk>
|
|
|