You are viewing the version of this documentation from Perl blead. This is the main development branch of Perl. (git commit ac147137186e96998460330acb00a2a78f0a51b6)

CONTENTS

NAME

ExtUtils::ParseXS::Node - Classes for nodes of an Abstract Syntax Tree

SYNOPSIS

# 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

DESCRIPTION

This API is currently private and subject to change.

The ExtUtils::ParseXS::Node class, and its various subclasses, hold the state for the nodes of an Abstract Syntax Tree (AST), which represents the parsed state of an XS file.

Each node is a hash of fields. Which field names are legal varies by the node type. The hash keys and values can be accessed directly: there are no getter/setter methods.

Each node may have a kids field which points to an array of all the children of that node: this is what provides the tree structure. In addition, 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 accessed in either of these ways:

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

Most object-valued node fields within a tree point only to their direct children; however, both INPUT_line and OUTPUT_line have an ioparam field which points to the IO_Param object associated with this line, which is located elsewhere in the tree.

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(), which are present in all subclasses. 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.

Secondly, 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 is 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.

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.

Note that parsing and code-generation are done as two separate phases; parse() should only build a tree and never emit code.

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.

The parse() and as_code() methods for some subclasses may have parameters in addition to those.

Some subclasses may also have additional helper methods.

Class Hierachy

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.

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

A typical XSUB might compile to a tree with a structure similar to the following.

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