EXTUTILS::PARSEXS::NODE(3perl)

πŸ“¦
version 5.44.0 Β· 3 versions
, in arch rolling

πŸ’– ExtUtils::ParseXS::Node β€” the Perl Programmers Reference Guide, but make it cute πŸ’–

okay bestie, welcome to the manpage for ExtUtils::ParseXS::Node, straight out of the Perl Programmers Reference Guide. this is the AST node class situation. it's giving compiler internals. let's get into it ✨


🌸 NAME 🌸

ExtUtils::ParseXS::Node β€” Classes for nodes of an Abstract Syntax Tree πŸ¦‹


✨ SYNOPSIS ✨

so here's the whole vibe in code form, no notes:

# Create a node to represent the Foo part of an XS file; then
# top-down parse it into a subtree; then top-down emit the
# contents of the subtree as C code.

my $foo = ExtUtils::ParseXS::Node::Foo->new();
$foo->parse(...)
    or die;
$foo->as_code(...);
print STDERR $foo->as_concise(1); # for debugging

like, make a Foo node, parse it top-down into a subtree, then emit that subtree's contents top-down as C code. and if you wanna see what's going on, as_concise(1) to STDERR is your debug slay. πŸ’…


πŸ’œ DESCRIPTION πŸ’œ

🚨 heads up bestie: this API is currently private and subject to change. don't build your whole personality on it yet.

the ExtUtils::ParseXS::Node class, plus all its various subclasses, hold the state for the nodes of an Abstract Syntax Tree (AST) β€” and that AST represents the parsed state of an XS file. iykyk. 🧚

every node is a hash of fields. which field names are legal varies by the node type. and here's the thing β€” you access the hash keys and values directly: there are no getter/setter methods. we're going straight to the hash, no middleman, main character energy. 😌

each node may have a "kids" field which points to an array of all the children of that node β€” that's literally what makes it a tree 🫢. on top of that, some of those kids may also have direct links from fields for quick access. for example, the "xsub_decl" child object of an "xsub" object can be reached in either of these two ways:

$xsub_object->{kids}[0]
$xsub_object->{decl}

most object-valued node fields inside a tree point only to their direct children. HOWEVER β€” and this is the plot twist 😭 β€” both "INPUT_line" and "OUTPUT_line" have an "ioparam" field which points to the "IO_Param" object associated with this line, and that guy is located elsewhere in the tree. not a direct child. just vibing somewhere else. iconic.

the various "foo_part" nodes divide the parsing of the main body of an XSUB into sections where different sets of keywords are allowable, and where various bits of code can be conveniently emitted. ✨


πŸŽ€ Methods πŸŽ€

there are two main methods in addition to new(), and they're present in all subclasses. ok so:

first, parse() consumes lines from the source to satisfy the construct being parsed. it may itself create objects of lower-level constructs and call parse on them. for example, Node::xbody::parse() may create a "Node::input_part" node and call parse() on it, which will create "Node::INPUT" or "Node::PREINIT" nodes as appropriate, and so on. it's turtles all the way down, bestie. 🐒

second, as_code() descends its sub-tree, outputting the tree as C code. πŸ’…

the as_concise() method returns a line-per-node string representation of the node and any children. most node classes just inherit this method from the base "Node" class. it's intended mainly for debugging. πŸ”

some nodes also have an as_boot_code() method for adding any code to the boot XSUB. this returns two array refs: one containing a list of code lines to be inserted early into the boot XSUB, and a second for later lines. two refs, two moods. πŸ™ˆ

finally, in the IO_Param subclass, as_code() is replaced with "as_input_code" and as_output_code(), since that node may need to generate two sets of C code β€” one to assign a Perl argument to a C variable, and the other to return the value of a variable to Perl. double duty, she works hard. πŸ‘‘

⭐ note that parsing and code-generation are done as two separate phases; parse() should only build a tree and never emit code. don't make her do both jobs at once, that's not the assignment.

in addition to $self, methods may commonly have some of these parameters:

  • $pxs β€” an "ExtUtils::ParseXS" object which contains the overall processing state. in particular, it has warning and croaking methods, and holds the lines read in from the source file for the current paragraph. πŸ“š
  • $xsub β€” for nodes related to parsing an XSUB, the current "ExtUtils::ParseXS::xsub" node being processed.
  • $xbody β€” for nodes related to parsing an XSUB, the current "ExtUtils::ParseXS::xbody" node being processed. note that in the presence of a "CASE" keyword, an XSUB can have multiple bodies. oh she contains multitudes. πŸ’–

the parse() and as_code() methods for some subclasses may have parameters in addition to those. some subclasses may also have additional helper methods. so many little bonus features, obsessed. ✨


πŸ¦‹ Class Hierachy πŸ¦‹

(preserving the original's spelling, bestie, i'm not touching that πŸ’€)

"Node" and its sub-classes form the following inheritance hierarchy. various abstract classes are used by concrete subclasses where the processing and/or fields are similar: for example, "CODE", "PPCODE" etc all consume a block of uninterpreted lines from the source file until the next keyword, and emit that code, possibly wrapped in "#line" directives. this common behaviour is provided by the "codeblock" class. sharing is caring fr fr. 🫢

    Node
        XS_file
        preamble
        C_part
        C_part_POD
        C_part_code
        C_part_postamble
        cpp_scope
        global_cpp_line
        BOOT
        TYPEMAP
        pre_boot
        boot_xsub
        xsub
        xsub_decl
        ReturnType
        Param
            IO_Param
        Params
        xbody
        input_part
        init_part
        code_part
        output_part
        cleanup_part
        autocall
        oneline
            MODULE
            REQUIRE
            FALLBACK
            include
                INCLUDE
                INCLUDE_COMMAND
            NOT_IMPLEMENTED_YET
            CASE
            enable
                EXPORT_XSUB_SYMBOLS
                PROTOTYPES
                SCOPE
                VERSIONCHECK
        multiline
            multiline_merged
                C_ARGS
                INTERFACE
                INTERFACE_MACRO
                OVERLOAD
            ATTRS
            PROTOTYPE
            codeblock
                CODE
                CLEANUP
                INIT
                POSTCALL
                PPCODE
                PREINIT
        keylines
            ALIAS
            INPUT
            OUTPUT
        keyline
            ALIAS_line
            INPUT_line
            OUTPUT_line

🌈 Abstract Syntax Tree structure 🌈

a typical XS file might compile to a tree with a node structure similar to the following. note that this is unrelated to the inheritance hierarchy shown above β€” different tree, different energy, don't get it twisted. πŸ™ˆ

in this example, the XS file includes another file, and has a couple of XSUBs within a "#if/#else/#endif". note that a "cpp_scope" node is the parent of all the nodes within the same branch of an "#if", or in the absence of "#if", within the same file. 🌸

    XS_file
        preamble
        C_part
            C_part_POD
            C_part_code
        C_part_postamble
        cpp_scope: type="main"
            MODULE
            PROTOTYPES
            BOOT
            TYPEMAP
            INCLUDE
                cpp_scope: type="include"
                    xsub
                        ...
            global_cpp_line: directive="ifdef"
            cpp_scope: type="if"
                xsub
                    ...
            global_cpp_line: directive="else"
            cpp_scope: type="if"
                xsub
                    ...
            global_cpp_line: directive="endif"
            xsub
                ...
        pre_boot
        boot_xsub

and a typical XSUB might compile to a tree with a structure similar to this one. so pretty. ✨

    xsub
        xsub_decl
            ReturnType
            Params
                Param
                Param
                ...
        CASE   # for when a CASE keyword being present implies multiple
               # bodies; otherwise, just a bare xbody node.
            xbody
                # per-body copy of declaration Params, augmented by
                # data from INPUT and OUTPUT sections
                Params
                    IO_Param
                    IO_Param
                    ...
                input_part
                    INPUT
                        INPUT_line
                        INPUT_line
                        ...
                    PREINIT
                init_part
                    INIT
                code_part
                    CODE
                output_part
                    OUTPUT
                        OUTPUT_line
                        OUTPUT_line
                        ...
                    POSTCALL
                cleanup_part
                    CLEANUP
        CASE
            xbody
                ...

aaaand that's the whole page bestie, you ate it, no crumbs left πŸ“πŸ’…

oh and for the record, this was perl v5.44.0, dated 2026-10-17, and it lives in the Perl Programmers Reference Guide as ExtUtils::ParseXS::Node(3perl). go forth and parse. πŸŽ€πŸ¦‹βœ¨

πŸ“¦ 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