XS::Pa...ublike(3pm)

πŸ’… XS::Parse::Sublike β€” the manual page, bestie edition

okay so you found XS::Parse::Sublike(3pm) in the User Contributed Perl Documentation section and you're like "what is this" β€” bestie, buckle up, we're going in 🌸


✨ NAME ✨

XS::Parse::Sublike β€” XS functions to assist in parsing sub-like syntax. it's giving "very specific tool for very specific people" and honestly? iconic.


🌈 DESCRIPTION 🌈

So this module hands you some XS functions to help you write parsers for sub-like syntax. Who is this for? Primarily the girlies writing keyword plugins using the PL_keyword_plugin hook mechanism. That's the vibe. πŸŽ€

real talk: it is unlikely to be of much use to anyone else. and it is highly unlikely to be any use at all when you're writing actual perl code with it. If you are not writing a keyword plugin using XS, this module is not for you. no cap. πŸ™ˆ

Also, and this is important so I'm saying it twice: this module is currently experimental. the design is still evolving and subject to change. Later versions may break ABI compatibility, which means any module depending on it will need changes, or at minimum a rebuild. so like… don't get too attached to the current shape of things, bestie. πŸ’€


πŸ‘‘ XS FUNCTIONS πŸ‘‘

🌟 boot_xs_parse_sublike

void boot_xs_parse_sublike(double ver)

Call this from your BOOT section to initialise the module and the parsing hooks. that's literally its whole job. so demure.

ver should either be 0 or a decimal number for the module version requirement. like so:

boot_xs_parse_sublike(0.04);

πŸ¦‹ xs_parse_sublike

int xs_parse_sublike(const struct XSParseSublikeHooks *hooks, void *hookdata, OP **op_ptr)

This one does the actual parsing of a sub-like keyword, main character energy fr. It expects the lexer to already be sitting just after the introduction keyword has been consumed, and then it proceeds to parse:

  • an optional name
  • a list of attributes
  • a signature (only if it's enabled by use feature 'signatures')
  • and the code body

The return value and op_ptr can be used directly from the keyword plugin function. The intended use is that you invoke this function from there and return the result directly. slay.

If you want more automated handling of keywords, go look at register_xs_parse_sublike instead. ✨

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. opaque. mysterious. we love her. πŸ’œ

πŸ’– register_xs_parse_sublike

void register_xs_parse_sublike(const char *keyword,
  const struct XSParseSublikeHooks *hooks, void *hookdata)

This installs a set of parsing hooks to be associated with the given keyword. Once you do that, the keyword gets handled automatically by a keyword parser that XS::Parse::Sublike itself installed. so it's basically plug and play, bestie.

Here's the flow: when the keyword is encountered, the hook's permit function is tested first to see if the keyword is permitted at this point. If that 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. (yes, same deal as before. consistent queen. πŸ’…)

🌸 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, and that keyword is either sub or the name of another sub-like keyword which was previously registered using register_xs_parse_sublike. Then it proceeds to parse the subsequent syntax similar to how it would have parsed if it'd been encountered by the module's own keyword parser plugin β€” except that the second set of hooks given here also take effect. two hook sets, one parse. it's giving collab. 🫢

Breakdown of the cases:

  • 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 be 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. so… noted, bestie. πŸ“

🧚 xps_signature_add_param

void xps_signature_add_param(struct XSParseSublikeContext *ctx,
   struct XPSSignatureParamDetails *details);

Since version 0.31; experimental. πŸ§ͺ

This experimental function may only be called during the start_signature or finish_signature hook stages. It inserts extra signature parameters β€” either at the beginning (when called by the start hook), or at the end (when called by the finish hook). It takes the details of the parameter to add from an addressed structure, which has the following fields:

struct XPSSignatureParamDetails {
   U32 ver;

   char sigil;
   PADOFFSET padix;
};

The caller must set the ver field equal to XSPARSESUBLIKE_ABI_VERSION. don't skip that. πŸ’…

The sigil field gives the leading sigil of the parameter:

  • $ for mandatory scalars
  • @ or % for a final slurpy

The padix field gives the pad offset for a pad variable to store the value into. The caller is (currently) responsible for creating that pad variable. so that's on you, girl. πŸŽ€

At the present version, this API cannot create optional, or named parameters. These abilities may be added in a later version which expands on the structure's definition to add new fields to support this. future plans, not current facts. πŸ’­

⭐ xps_signature_query_*

IV xps_signature_query_params(struct XSParseSublikeContext *ctx);

IV xps_signature_query_optparams(struct XSParseSublikeContext *ctx);

char xps_signature_query_slurpy(struct XSParseSublikeContext *ctx);

Since version 0.37; experimental. πŸ§ͺ

These experimental functions may only be called during the start_signature or finish_signature hook stages. They query details about the accumulated set of signature parameters. here's what each one gives you:

  • _params returns the total number of defined parameters β€” counting all mandatory, optional, and a final slurpy if present.
  • _optparams returns a count of only the optional parameters.
  • _slurpy returns the sigil character of a final slurpy parameter (@ or %), or zero if no slurpy parameter is present.

🌈 PARSE CONTEXT 🌈

The various hook stages all share state about the ongoing parse process using various fields of the XSParseSublikeContext structure. one struct, many stages, all gossiping through shared fields. πŸ’–

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. so you can absolutely meddle. iconic. πŸ‘‘

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. ⚠️

Now the action flags themselves, one by one, no skipping:

  • 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. pretending to be reachable while not being reachable? the audacity. πŸ’€

  • 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_INSTALL_LEXICAL β€” If set, the newly-constructed CV will be installed into the currently compiling lexical pad as its given name. This is only available on Perl version 5.18 or above, and conflicts with the alternative of XS_PARSE_SUBLIKE_ACTION_INSTALL_SYMBOL. This is set by default if a name was found and the my keyword appeared before the construction.
  • 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 use 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, like 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. fresh HV per parse, no lingering. we love a clean exit. 🧹✨


still more to come, bestie β€” this was only part 1 πŸ¦‹

πŸ¦‹ 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_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.
  • XS_PARSE_SUBLIKE_FLAG_ALLOW_PKGNAME β€” Since version 0.31.

If not set, then fully-qualified identifiers that include a package name are not allowed when declaring a named function. If all hooks agree by all setting the flag, then the name may be fully-qualified to add the newly-declared function into a different package.

  • XS_PARSE_SUBLIKE_FLAG_SIGNATURE_NAMED_PARAMS β€” If set, use the extended signature parser of this module when parsing a signature and additionally permit the use of named parameter syntax, as documented in Sublike::Extended.
  • XS_PARSE_SUBLIKE_FLAG_SIGNATURE_PARAM_ATTRIBUTES β€” If set, use the extended signature parser of this module when parsing a signature and additionally permit the use of attribute declarations on parameter variables, as documented in Sublike::Extended.
  • XS_PARSE_SUBLIKE_FLAG_SIGNATURE_REFALIAS β€” If set, use the extended signature parser of this module when parsing a signature and additionally permit the use of refalias parameter syntax, as documented in Sublike::Extended.

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 "filter_attr" Stage πŸ’–

bool (*filter_attr)(pTHX_ struct XSParseSublikeContext *ctx,
   SV *attr, SV *val, void *hookdata);

If this optional stage is defined, 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 Signature 🧚

If the perl version supports subroutine signatures, and the feature is enabled at this point, then an optional signature is expected.

Since version 0.31: if the open parenthesis of a signature declaration is found, then the start_signature stage is invoked. Once the signature has been parsed, the finish_signature stage is invoked.

void (*start_signature)(pTHX_ struct XSParseSublikeContext *ctx, void *hookdata);

void (*finish_signature)(pTHX_ struct XSParseSublikeContext *ctx, void *hookdata);

Code in either of these hook stages is permitted to call xps_signature_add_param, or any of the xps_signature_query_*() functions.

🌈 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 a subroutine signature was 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>


Okay bestie, that's the whole vibe of this page πŸ’– This manual came from perl v5.42.3, dated 2026-09-17, and it's the doc for XS::Pa...ublike(3pm). Go forth and parse like the icon you are πŸ’…βœ¨

πŸ“¦ where this page comes from