chapel-py

Python bindings for Chapel’s frontend library, Dyno.

The purpose of this library is to allow programmers to easily create tools for the Chapel programming language that would be more difficult to write using C++ (the native language in which the Chapel frontend library is written).

For example, here’s a toy program that prints the names of all things declared anywhere in myfile.chpl.

from chapel import *

ctx = Context()
ast = ctx.parse("myfile.chpl")

all_names = set()
for node in postorder(ast):
    if isinstance(node, NamedDecl):
        all_names.add(node.name())

for name in all_names:
    print(name)

If myfile.chpl contains the following:

module myfile {
    var x = 1+1;
    var y = x+1;

    record R {

    }
}

Then the program will print out something like the following:

R
y
x
myfile

Note

The Chapel Python bindings are not yet fully mature. The API is subject to change and is not considered stable. Users of this library should be prepared to update their code as the library evolves.

Installation

Make sure that you have a from-source build of Chapel available in your CHPL_HOME. Currently, the build script also requires having LLVM available in your path. The build script also requires that the development package of Python be installed (for many package managers this is called python3-devel). With those constraints met, you can just run make chapel-py-venv:

This will allow you to use the Python bindings from a Python script run with $CHPL_HOME/util/config/run-in-venv-with-python-bindings.bash python3, instead of just python3. If you wish to install the Python bindings in your system Python, run python3 -m pip install $CHPL_HOME/tools/chapel-py.

Usage

The library is split into several major components:

  • The chapel module provides the AST node class hierarchy and the Context object. It also provides some higher-level, pure Python implementations of certain utility functions. For instance, it provides the preorder and postorder traversal iterators and a match function to perform AST pattern matching.

  • The chapel.replace module provides the “replacer API”, which is intended to perform transformations on existing Chapel files for various reasons. For instance, deprecations and syntax changes can be performed automatically using the replacer API, by finding AST patterns and performing string substitution.

  • The chapel.lsp module provides a few helpers to transform Dyno types to LSP (Language Server Protocol) types. This module requires the lsprotocol package.

chapel

The main entry point to the Chapel Python API is the Context object. This is a wrapper around the C++ construct of the same name. The Context in Dyno is responsible for memoizing computations, interning strings, and more. The Python wrapper around this object has methods that can be used to get started with processing Chapel programs; one such method is parse, which accepts a file path and returns a list of Chapel AST nodes that represent this file.

At compile-time, chapel-py generates a class hierarchy of Python objects, with base class AstNode. A class is created for each of the AST nodes understood by Dyno. Thus, one might write:

from chapel import *

ctx = Context()
asts = ctx.parse("myfile.chpl")
print("it's a module" if isinstance(asts[0], Module) else "it's not a module")

Here, the Python isinstance builtin is used to determine if the first AST node returned by parse is a module (it should be!)

Because the AST nodes form a class hierarchy, it’s possible to perform a more general check; the following example prints “It’s a loop!” for all loops (do- while, for, foreach, etc.), and “It’s not a loop…” otherwise.

def check(node):
    if isinstance(node, Loop):
        print("It's a loop!")
    else:
        print("It's not a loop...")

The AST nodes from the Python API are iterable; iterating over a node yields its children. Thus, one might print all the declarations in a module as follows:

def print_decls(mod):
    for child in mod:
        if isinstance(child, NamedDecl):
            print(child.name())

Full AST traversals can be built on top of this functionality. Below is the definition for postorder from the chapel module:

def postorder(node):
    """
    Recursively visit the given AST node, going in post-order (children-then-parent)
    """
    for child in node:
        yield from postorder(child)
    yield node

To find the list of available methods for each AST node class, the current best practice is to consult the generated $CHPL_HOME/tools/chapel-py/src/chapel/core/__init__.pyi file. This is generated by default when the Python bindings are built and is the most up-to-date source of information on the API.

The chapel module also provides convenience functions for working with the library. For instance, it provides the postorder and preorder iterators (the implementation of the former is included above). It also provides a couple of more advanced helpers for dealing with Chapel ASTs.

chapel.parse_attribute

The parse_attribute function, given a “description” of an attribute (its name and formal list), tries to parse an Attribute AST node. This function accounts for named and unnamed actuals, reordering, etc. For instance, given an “attribute schema”:

attr = ("doXYZ", ["x", "y", "z"])

And the following Chapel attribute:

@doXYZ("hello", z = "world", y = "!")

The function returns:

{"x": "hello", "y": "!", "z": "world"}

This function is used in the Chapel linter to handle silencing warnings:

def ignores_rule(node, rulename):
    ag = node.attribute_group()

    if ag is None: return False
    for attr in ag:
        attr_call = chapel.parse_attribute(attr, IgnoreAttr)
        if attr_call is None: continue

        ignored_rule = attr_call["rule"]
        if ignored_rule is not None and ignored_rule.value() == rulename:
            return True

    return False

chapel.match_pattern

This function provides general pattern matching functionality to enable users of the Python API to rapidly find “interesting” locations in the AST. It supports arbitrary levels of nesting, as well as “named variables” to easily retrieve deeply nested AST nodes after a pattern has matched.

Generally, a call to match_pattern takes an AST node and a pattern (what constitutes a pattern is explained below). If the pattern matches, the function returns a Python dict that maps pattern variables to their corresponding AST nodes; an empty dict is returned if no pattern variables were used. If the pattern does not match, the function returns None.

To explain the possible patterns, it’s helpful to have an example AST. We will use the following Chapel function, and its AST myFn, in the following examples:

proc f(x: int, y: int) {
    var z = 1+2;
    return x+y+z;
}

The simplest example of pattern is an AST class. For instance:

print(chapel.match_pattern(myFn, Function)) # Prints "{}"

When a function AST node myFn is matched against the Function pattern, the match is successful; since no pattern variables were used, this results in an empty dictionary {}.

A list can be used to represent patterns of AST nodes with children. To match a function with exactly two arguments:

print(chapel.match_pattern(myFn, [Function, Formal, Formal, Block])) # Prints "{}"

Since we still haven’t used any pattern variables, the result of match_pattern still returns {}. However, having matched the pattern, it would be cumbersome to attempt to retrieve each of the two formals from the list: we’d need to access the function’s children again, by their index. Since Formal nodes are direct children of the Function, this isn’t too inconvenient; however, conceivably, the nodes of interest could be further down in the AST from the parent. This is where pattern variables come in. Instead of writing Formal, we can write ("?f1", Formal). This will cause the pattern matcher to save the AST node matching Formal into the variable f1.

pat = [Function, ("?f1", Formal), ("?f2", Formal), Block]
print(chapel.match_pattern(myFn, pat)) # Prints "{ 'f1': ..., 'f2': ... }"

The dictionary returned by match_pattern can then be queried by the variables to retrieve the formals.

We can further restrict our pattern to require formals with ‘simple’ type expressions (identifiers).

pat = [Function, [Formal, Identifier], [Formal, Identifier], Block]
print(chapel.match_pattern(myFn, pat)) # Prints "{}"

Pattern variables can still be used with list patterns like [Formal, Identifier]. This is done by adding the pattern variable string to the front of the list.

pat = [Function, ["?f1", Formal, Identifier], ["f2", Formal, Identifier], Block]
print(chapel.match_pattern(myFn, pat)) # Prints "{ 'f1': ..., 'f2': ... }"

Some other useful features of the pattern library:

  • The rest pattern can be used as part of a list to indicate that you don’t care about the remaining AST children, however many there are.

  • A variable without an AST node, ("?x") can be used by itself to match any AST node and store it in x.

  • A set can be used to represent a disjunctive or pattern. For example, set([Begin, Cobegin]) will match either a Begin or a Cobegin node.

chapel.each_matching

This function combines the operation of preorder and match_pattern to iterate an AST and yield all nodes matching the given pattern. Concretely, given a pattern, it yields the node and the variables resulting from the match. The following snippet will print one line for each binary operation, listing the operation itself and the operation’s two operands.

for (op, variables) in chapel.each_matching(myFn, [OpCall, "?l", "?r"]):
    print("Found an operation ", op.op(), "with operands: ", variables["l"], variables["r"])

chapel.replace

The chapel.replace module is used for writing “replacer scripts”. The motivation for this module is evolving the Chapel language. As the language develops, we tend to shift the patterns we prefer, and modify unstable language syntax. When modifying existing code to match the new standards, we either have to perform the changes manually, or resort to “general” tools like sed or awk. However, the trouble with these tools is that they are suited for modifying streams of text. When modifying programs in a language, it is more natural to work with a structured representation – the AST. Thus, the chapel.replacer module provides utilities to modify a file by traversing the ASTs contained within, and generating a list of substitutions.

Although the AST is used to find places in the code where changes must be made, the changes themselves are performed using string operation. This is motivated by many reasons:

  • Dyno does not have good support for modifying ASTs (they are immutable).

  • If an AST is modified, it should be printed back to the file with only those modifications; however, this would require the Chapel syntax printer to be able to preserve most of the original format of the text.

  • Writing plain code, such as 1+1, is often easier than creating an AST node (PlusNode(IntNode(1), IntNode(1))).

The chapel.replace module provides a driver function run, which, when given a source of changes (described below), takes over the execution of the program. It registers and parses command line arguments, and handles file modifications. Thus, given an AST traversal, you end up with a fully-featured command-line script ready to be pointed at files.

usage: replace [-h] [--suffix SUFFIX] [--in-place] [filenames ...]

A tool to search-and-replace Chapel expressions with others

positional arguments:
  filenames

options:
  -h, --help       show this help message and exit
  --suffix SUFFIX
  --in-place`

The ‘source of changes’ is a Python iterator that should accept two arguments: rc (for ‘replacement context’) and root (for the AST node at which the traversal begins). A very simple (albeit completely pointless and semantically incorrect) example is the following script, which replaces all occurrences of the number 42 with meaningOfLife:

def replace_all_42(rc, root):
    for (num, _) in each_matching(root, IntLiteral):
        if num.text() == '42': yield (num, 'meaningOfLife')

run(replace_all_42)

A more practical example is renaming methods. Note that this is not amenable to naive substitution: we don’t want to accidentally rename non-methods that happen to have the same name, or even locally declared functions inside other functions in a record or class. Consider renaming the enterThis method to enterContext (this is a real change that was performed in the Chapel language in 1.32, though it was not done automatically with the help of this tool). In the following snippet, only the proc labeled (1) should be renamed. This is because enterThis is actually a method. On the other hand, (2), even though it’s declared within R’s curly braces, is actually a locally defined function, and not a method on R. (3) is a freestanding function, and thus should also not be renamed.

record R {
    proc enterThis() {} // (1)
    proc f() {
        proc enterThis() {} // (2)
    }
}
proc enterThis() {} // (3)

This can be implemented using the following iterator:

def replace_enter_this(rc, root):
    for (fn, _) in each_matching(root, Function):
        if fn.name() == "enterThis" and fn.is_method():
            yield (fn, lambda txt: txt.replace("enterThis", "enterContext", 1))

In this case, instead of yielding a pair of the node-to-replace and the replacement text, the iterator produces a lambda, which will be fed the node’s current string representation (proc enterThis() {...). Using this lambda, we perform a simple substitution, renaming enterThis to enterContext with Python’s regular replace method.

Finally, the following script was used to automatically insert interfaces into records and classes that provided the corresponding functionality. It was used to update about 150 files (including Chapel modules and tests). This script implements the following features:

  • Detecting particular signatures of the init method specific to deserialization

  • Always printing the supported interfaces in a specific order

  • Supporting both primary and secondary methods, including a mix of both

  • Adding a new interface list or modifying an existing one

def tag_aggregates_with_io_interfaces(rc, root):
    aggrs_to_change = defaultdict(lambda: set())
    names_to_tag = defaultdict(lambda: set())

    for (fn, _) in chapel.each_matching(root, Function):
        if not fn.is_method(): continue
        name = fn.name()

        if name == "serialize":
            tag = "writeSerializable"
        elif name == "deserialize":
            tag = "readDeserializable"
        elif name == "init":
            formal_names = []
            for child in fn:
                if not isinstance(child, Formal): continue
                if child.name() == "this": continue
                formal_names.append(child.name())

            if len(formal_names) >=2 and formal_names[-1] == "deserializer" and formal_names[-2] == "reader":
                tag = "initDeserializable"
            else:
                continue
        else:
            continue

        if fn.is_primary_method():
            aggrs_to_change[fn.parent().unique_id()].add(tag)
            continue

        this_receiver = fn.this_formal()
        names_to_tag[rc.node_exact_string(this_receiver)].add(tag)

    def build_tag_str(tags):
        if len(tags) == 3: return "serializable"

        # tags have a preferred order, so just use an if-else chain to make that work
        the_order = ["writeSerializable", "readDeserializable", "initDeserializable"]
        return ", ".join(t for t in the_order if t in tags)

    for (record, _) in chapel.each_matching(root, AggregateDecl):
        tags = set()
        if record.unique_id() in aggrs_to_change:
            tags |= aggrs_to_change[record.unique_id()]
        if record.name() in names_to_tag:
            tags |= names_to_tag[record.name()]

        if len(tags) == 0: continue

        tag_str = build_tag_str(tags)
        record_text = rc.node_exact_string(record)
        curlypos = record_text.find("{")
        colonpos = record_text.find(":")

        if colonpos >= 0 and colonpos < curlypos:
            new_text = record_text.replace(" {" , ", " + tag_str + " {" , 1)
        else:
            new_text = record_text.replace(record.name(), record.name() + " : " + tag_str, 1)

        yield (record, new_text)

API

chapel

Chapel’s Python bindings provide an API to interact with Chapel’s frontend compiler from Python.

chapel.preorder(node)

Recursively visit the given AST node, going in pre-order (parent-then-children)

chapel.postorder(node)

Recursively visit the given AST node, going in post-order (children-then-parent)

chapel.is_deprecated(node: AstNode) bool

Returns true if node is marked with a @deprecated attribute

chapel.is_unstable(node: AstNode) bool

Returns true if node is marked with a @unstable attribute

chapel.is_docstring_comment(comment: Comment) bool

comment is a docstring if it doesn’t begin with ‘//’

class chapel.SiblingMap(top_level_modules: List[AstNode])

Represents a mapping of nodes to their siblings. This is most useful for finding the docstring of a node.

class SiblingVisitor
enter_AstNode(node: AstNode)
exit_AstNode(node: AstNode)
visit(node)
get_sibling(node: AstNode) AstNode | None

Get the sibling of a node, if it exists

chapel.get_docstring(node: AstNode, sibling_map: SiblingMap) str | None

Get the docstring for a node, if it exists

chapel.parse_attribute(attr: Attribute, attribute: Tuple[str, Sequence[str]])

Given an Attribute AST node, and a description of the attribute in the form (name, formal_names), return a mapping of formal names to their values in the attribute call. Raise errors if the call is malformed in some way.

chapel.match_pattern(ast, pattern)

Matches the given AST against the given pattern. Patterns are specified as AST node classes, strings, or lists thereof. Here’s a summary:

A single node with any number of children:

chapel.Nodetype

Any node, saved in a variable:

“?x”

Any node at all, not saved in a variable:

“”

A single node with any number of children, saved in a variable:

(“?x”, chapel.Nodetype)

A single node with no children at all:

[chapel.Nodetype]

A single node with no children, saved in a variable:

[“?x”, chapel.Nodetype]

A single node with two children, expressed as patterns P1 and P2:

[chapel.Nodetype, P1, P2]

A single node with at least two children:

[chapel.Nodetype, P1, P2, rest]

An addition node in which both arguments are equal:

[chapel.OpCall, “?x”, “x”]

chapel.each_matching(node, pattern, iterator=<function preorder>)
chapel.files_with_contexts(files: List[str], setup: Callable[[Context], None] | None = None)

Some files might have the same name, which Dyno really doesn’t like. Stratify files into “buckets”; within each bucket, all filenames are unique. Between each bucket, re-create the Dyno context to avoid giving it conflicting files.

For each newly-created context, call the setup function with it.

Yields files from the argument, as well as the context created for them.

chapel.files_with_stdlib_contexts(files: List[str], setup: Callable[[Context], None] | None = None)

Like files_with_contexts, but also includes the standard library in the context.

chapel.range_to_tokens(rng: Location, lines: List[str]) List[Tuple[int, int, int]]

Convert a Chapel location to a list of token-compatible ranges. If a location spans multiple lines, it gets split into multiple tokens. The lines and columns are zero-indexed.

Returns a list of (line, column, length).

chapel.range_to_lines(rng: Location, lines: List[str]) List[str]

Convert a Chapel location to a list of strings

chapel.range_to_text(rng: Location, lines: List[str]) str

Convert a Chapel location to a single string

chapel.get_file_lines(context: Context, node: AstNode) List[str]

Get the lines of the file containing the given node

chapel.is_basic_literal_like(node: AstNode) Literal | None

Check for “basic” literals: basically, 1, “hello”, -42, etc. Returns the “underlying” literal removing surrounding AST (1, “hello”, 42). This helps do type comparisons in more complex checks. If the node is not a basic literal, returns None.

chapel.is_complex_literal(node: AstNode) Tuple[Literal, Literal] | None

Check for complex number literals: 1+2i, -42-3i, etc. Returns a tuple of the “underlying” literals, removing surrounding AST ((1, 2i), (42, 3i), etc.). This helps do type comparisons in more complex checks. If the node is not a complex literal, returns None.

chapel.is_literal_like(node: AstNode) bool

Returns true if the node is a literal-like node: either a “true” literal (1, “hello”, etc.) or something that isn’t a literal in the AST, but is a literal mathematically (-10, 10 + 2i).

chapel.is_unstable_module(node: AstNode)

Returns true if the given AST node is a module, and if it’s explicitly marked unstable.

chapel.in_unstable_module(node: AstNode)

Returns true if the given AST node is inside a module marked as unstable.

class chapel.AggregateDecl

A Chapel AggregateDecl AST node

decls_or_comments(self) Iterator[AstNode]

Get the declarations and comments of this AggregateDecl node

inherit_exprs(self) Iterator[AstNode]

Get the inherit expressions of this AggregateDecl node

class chapel.AnonFormal

A Chapel AnonFormal AST node

intent(self) str

Get the intent for this AnonFormal node

type_expression(self) Optional[AstNode]

Get the type expression for this AnonFormal node

class chapel.AnyClassType

A Chapel AnyClassType AST node

class chapel.AnyComplexType

A Chapel AnyComplexType AST node

class chapel.AnyEnumType

A Chapel AnyEnumType AST node

class chapel.AnyImagType

A Chapel AnyImagType AST node

class chapel.AnyIntType

A Chapel AnyIntType AST node

class chapel.AnyIntegralType

A Chapel AnyIntegralType AST node

class chapel.AnyIteratorClassType

A Chapel AnyIteratorClassType AST node

class chapel.AnyIteratorRecordType

A Chapel AnyIteratorRecordType AST node

class chapel.AnyNumericType

A Chapel AnyNumericType AST node

class chapel.AnyOwnedType

A Chapel AnyOwnedType AST node

class chapel.AnyPodType

A Chapel AnyPodType AST node

class chapel.AnyRealType

A Chapel AnyRealType AST node

class chapel.AnyRecordType

A Chapel AnyRecordType AST node

class chapel.AnySharedType

A Chapel AnySharedType AST node

class chapel.AnyThunkRecordType

A Chapel AnyThunkRecordType AST node

class chapel.AnyType

A Chapel AnyType AST node

class chapel.AnyUintType

A Chapel AnyUintType AST node

class chapel.AnyUninstantiatedType

A Chapel AnyUninstantiatedType AST node

class chapel.AnyUnionType

A Chapel AnyUnionType AST node

class chapel.Array

A Chapel Array AST node

exprs(self) Iterator[AstNode]

Get the expressions from this Array node

has_trailing_comma(self) bool

Check if this Array node has a trailing comma

is_associative(self) bool

Check if this Array node is associative

class chapel.ArrayType

A Chapel ArrayType AST node

class chapel.As

A Chapel As AST node

rename(self) AstNode

Get the rename for this As node

symbol(self) AstNode

Get the symbol for this As node

class chapel.AstNode

The base type of Chapel AST nodes

attribute_group(self) Optional[AttributeGroup]

Get the attribute group, if any, associated with this node

block_header(self) Optional[Location]

Get the header Location of this block-like AstNode node

called_fn(self) Optional[AstNode]

Get the function being invoked by this node

creates_scope(self) bool

Returns true if this AST node creates a scope

curly_braces_location(self) Optional[Location]

Get the Location of the curly braces of this AstNode node

dump(self) None

Dump the internal representation of the given AST node

location(self) Location

Get the location of this AST node in its file

paren_location(self) Optional[Location]

Get the Location of the parentheses of this AstNode node

parent(self) Optional[AstNode]

Get the parent node of this AST node

parent_symbol(self) Optional[AstNode]

Get the parent symbol of this AST node (e.g., module, variable, etc.)

pragmas(self) Set[str]

Get the pragmas of this AST node

resolve(self) Optional[ResolvedExpression]

Perform resolution on code surrounding this node to determine its type and other information.

resolve_via(self, arg0: TypedSignature) Optional[ResolvedExpression]

Use a given function’s type information to determine the information of this node.

scope(self) Optional[Scope]

Get the scope for this AST node

scope_resolve(self) Optional[ResolvedExpression]

Perform scope resolution on code surrounding this node to retrieve its to-ID and collect errors.

tag(self) str

Get a string representation of the AST node’s type

type(self) Optional[Tuple[str, Optional[ChapelType], Optional[Param]]]

Get the type of this AST node, as a 3-tuple of (kind, type, param).

unique_id(self) str

Get a unique identifier for this AST node

class chapel.Attribute

A Chapel Attribute AST node

actuals()

Get the actuals for this Attribute node

name(self) str

Get the name of this Attribute node

class chapel.AttributeGroup

A Chapel AttributeGroup AST node

get_attribute_named(self, arg0: str) Optional[AstNode]

Get the attribute with a particular name, if any

is_deprecated(self) bool

Check if this AttributeGroup contains the ‘deprecated’ attribute

is_unstable(self) bool

Check if this AttributeGroup contains the ‘unstable’ attribute

class chapel.BasicClassType

A Chapel BasicClassType AST node

class chapel.Begin

A Chapel Begin AST node

with_clause(self) Optional[WithClause]

Get the WithClause of this Begin node

class chapel.Block

A Chapel Block AST node

class chapel.BoolLiteral

A Chapel BoolLiteral AST node

value(self) bool

Get the value of this BoolLiteral node

class chapel.BoolParam

A Chapel BoolParam AST node

value(self) bool

Get the value of this boolean Param

class chapel.BoolType

A Chapel BoolType AST node

class chapel.BracketLoop

A Chapel BracketLoop AST node

is_maybe_array_type(self) bool

Check if this BracketLoop node may actually be a type

class chapel.Break

A Chapel Break AST node

target(self) Optional[Identifier]

Get the target from this Break node

class chapel.BuiltinType

A Chapel BuiltinType AST node

class chapel.BytesLiteral

A Chapel BytesLiteral AST node

class chapel.CFnPtrType

A Chapel CFnPtrType AST node

class chapel.CPtrType

A Chapel CPtrType AST node

class chapel.CStringLiteral

A Chapel CStringLiteral AST node

class chapel.CStringType

A Chapel CStringType AST node

class chapel.CVoidPtrType

A Chapel CVoidPtrType AST node

class chapel.Call

A Chapel Call AST node

actual(self, arg0: int) AstNode

Get the n’th actual of this Call node

actuals(self) Iterator[AstNode]

Get the arguments to this Call node

called_expression(self) AstNode

Get the expression invoked by this Call node

formal_actual_mapping(self) List[int]

Get the index of the function’s formal for each of the call’s actuals.

num_actuals(self) int

Get the number of actuals for this Call node

class chapel.Catch

A Chapel Catch AST node

body(self) Block

Get the body from this Catch node

has_parens_around_error(self) bool

Check if this Catch uses parentheses

target(self) Optional[Variable]

Get the error from this Catch node

class chapel.ChapelType

The base type of Chapel types

class chapel.Class

A Chapel Class AST node

class chapel.ClassType

A Chapel ClassType AST node

class chapel.Cobegin

A Chapel Cobegin AST node

task_bodies(self) Iterator[AstNode]

Get tasks from this Cobegin node

with_clause(self) Optional[WithClause]

Get the WithClause from this Cobegin node

class chapel.Coforall

A Chapel Coforall AST node

class chapel.Comment

A Chapel Comment AST node

text(self) str

Get the text from this Comment node

class chapel.ComplexParam

A Chapel ComplexParam AST node

class chapel.ComplexType

A Chapel ComplexType AST node

class chapel.CompositeType

A Chapel CompositeType AST node

decl(self) Optional[AstNode]

Get the chpl::uast::AstNode that declares this CompositeType

class chapel.Conditional

A Chapel Conditional AST node

condition(self) AstNode

Get the condition of this Conditional node

else_block(self) Optional[Block]

Get the else block of this Conditional node or None if no else block

is_expression_level(self) bool

Checks if this Conditional node is expression-level

then_block(self) Block

Get the then block of this Conditional node

class chapel.Context

The Chapel context object that tracks various frontend state

advance_to_next_revision(self, arg0: bool) None

Advance the context to the next revision

get_file_text(self, arg0: str) str

Get the text of the file at the given path

introspect_parsed_files(self) List[str]

Inspect the list of files that have been parsed by the Context

is_bundled_path(self, arg0: str) bool

Check if the given file path is within the bundled (built-in) Chapel files

parse(self, arg0: str) List[AstNode]

Parse a top-level AST node from the given file

set_module_paths(self, arg0: List[str], arg1: List[str]) None

Set the module path arguments to the given lists of module paths and filenames

track_errors(self) ErrorManager

Return a context manager that tracks errors emitted by this Context

class chapel.Continue

A Chapel Continue AST node

target(self) Optional[Identifier]

Get the target from this Continue node

class chapel.Decl

A Chapel Decl AST node

linkage(self) str

Get the linkage of this Decl node

linkage_name(self) Optional[AstNode]

Get the linkage name of this Decl node

visibility(self) str

Get the visibility of this Decl node

class chapel.DeclaredType

A Chapel DeclaredType AST node

class chapel.Defer

A Chapel Defer AST node

class chapel.Delete

A Chapel Delete AST node

exprs(self) Iterator[AstNode]

Get the expressions from this Delete node

class chapel.DoWhile

A Chapel DoWhile AST node

condition(self) AstNode

Get the condition of this DoWhole node

class chapel.Domain

A Chapel Domain AST node

exprs(self) Iterator[AstNode]

Get the expressions from this Domain node

used_curly_braces(self) bool

Check if the Domain node used curly braces

class chapel.DomainType

A Chapel DomainType AST node

class chapel.Dot

A Chapel Dot AST node

field(self) str

Get the field accessed in the Dot node

field_location(self) Location

Get the textual location of the Dot node’s field expression

receiver(self) AstNode

Get the receiver of the Dot node

to_node(self) Optional[AstNode]

Get the AST node that this Dot node refers to

class chapel.EmptyStmt

A Chapel EmptyStmt AST node

class chapel.Enum

A Chapel Enum AST node

class chapel.EnumElement

A Chapel EnumElement AST node

init_expression(self) Optional[AstNode]

Get the init expression of this EnumElement node

class chapel.EnumParam

A Chapel EnumParam AST node

value(self) AstNode

Get the value of this enum Param

class chapel.EnumType

A Chapel EnumType AST node

class chapel.ErroneousExpression

A Chapel ErroneousExpression AST node

class chapel.ErroneousType

A Chapel ErroneousType AST node

class chapel.Error

An error that occurred as part of processing a file with the Chapel compiler frontend

code_snippets(self) List[Tuple[Location, List[Location]]]

Get the locations of code snippets printed by this error

kind(self) str

Retrieve the kind (‘error’, ‘warning’) of this type of error

location(self) Location

Get the location at which this error occurred

message(self) str

Retrieve the contents of this error message

notes(self) List[Tuple[Location, str]]

Get the locations and text of additional notes printed by this error

type(self) Optional[str]

Retrieve the unique name of this type of error

class chapel.ErrorManager

A wrapper container to help track the errors from a Context.

class chapel.ExternBlock

A Chapel ExternBlock AST node

code(self) str

Get C code of this ExternBlock node

class chapel.ExternType

A Chapel ExternType AST node

class chapel.FnCall

A Chapel FnCall AST node

actuals()

Get the actuals of this FnCall node

used_square_brackets(self) bool

Check if this FnCall was made using square brackets

class chapel.FnIteratorType

A Chapel FnIteratorType AST node

class chapel.For

A Chapel For AST node

is_param(self) bool

Check if this For node is a param

class chapel.Forall

A Chapel Forall AST node

class chapel.Foreach

A Chapel Foreach AST node

class chapel.Formal

A Chapel Formal AST node

class chapel.ForwardingDecl

A Chapel ForwardingDecl AST node

expr(self) Optional[AstNode]

Get the expression of this ForwardingDecl node

class chapel.Function

A Chapel Function AST node

body(self) Optional[Block]

Get the body for this function

formal(self, arg0: int) Decl

Get the n’th Formal of this Function node

formals(self) Iterator[Decl]

Get the formals for this Function node

is_anonymous(self) bool

Check if this Function node is anonymous

is_inline(self) bool

Check if this Function node is marked inline

is_method(self) bool

Check if this Function node is a method

is_override(self) bool

Check if this Function node is an override

is_parenless(self) bool

Check if this Function node is parenless

is_primary_method(self) bool

Check if this Function node is a primary method

kind(self) str

Get the kind of this Function node

lifetime_clauses(self) Iterator[AstNode]

Get the lifetime clauses for this Function node

num_formals(self) int

Get the number of formals for this Function node

return_intent(self) str

Get the return intent of this Function node

return_type(self) Optional[AstNode]

Get the return type for this Function node

this_formal(self) Optional[Decl]

Get the this formal for this Function node

throws(self) bool

Check if this Function node is marked throws

where_clause(self) Optional[AstNode]

Get the where clause for this Function node

class chapel.FunctionSignature

A Chapel FunctionSignature AST node

formals(self) Iterator[Decl]

Get the formals for this FunctionSignature node

is_parenless(self) bool

Check if this FunctionSignature node is parenless

kind(self) str

Get the kind of this FunctionSignature node

return_intent(self) str

Get the return intent of this FunctionSignature node

return_type(self) Optional[AstNode]

Get the return type for this FunctionSignature node

this_formal(self) Optional[Formal]

Get the this formal for this FunctionSignature node

throws(self) bool

Check if this FunctionSignature node is marked throws

class chapel.FunctionType

A Chapel FunctionType AST node

class chapel.HeapBufferType

A Chapel HeapBufferType AST node

class chapel.Identifier

A Chapel Identifier AST node

name(self) str

Get the name of this Identifier node

to_node(self) Optional[AstNode]

Get the AST node that this Identifier node refers to

class chapel.ImagLiteral

A Chapel ImagLiteral AST node

text(self) str

Get the value of this ImagLiteral node

class chapel.ImagType

A Chapel ImagType AST node

class chapel.Implements

A Chapel Implements AST node

interface_expr(self) AstNode

Get the interface expression from this Implements node

interface_name(self) str

Get the interface name of this Implements node

is_expression_level(self) bool

Check if this Implements node is expression level

type_ident(self) Optional[Identifier]

Get the type identifier from this Implements node

class chapel.Import

A Chapel Import AST node

visibility(self) str

Get the visibility of this Import node

visibility_clauses(self) Iterator[VisibilityClause]

Get the visibility clauses of this Import node

class chapel.Include

A Chapel Include AST node

is_prototype(self) bool

Check if this Include node is for a prototype module

name(self) str

Get the name of this Include node

visibility(self) str

Get the visibility of this Include node

class chapel.IndexableLoop

A Chapel IndexableLoop AST node

index(self) Optional[Decl]

Get the index of this IndexableLoop node

is_expression_level(self) bool

Check if this IndexableLoop node is expression level

iterand(self) AstNode

Get the iterand of this IndexableLoop node

with_clause(self) Optional[WithClause]

Get the WithClause of this IndexableLoop node

class chapel.Init

A Chapel Init AST node

target(self) Identifier

Get the target of this Init node

class chapel.IntLiteral

A Chapel IntLiteral AST node

text(self) str

Get the value of this IntLiteral node

class chapel.IntParam

A Chapel IntParam AST node

value(self) int

Get the value of this integer Param

class chapel.IntType

A Chapel IntType AST node

class chapel.Interface

A Chapel Interface AST node

formals(self) Iterator[AstNode]

Get the formals for this Interface node

is_formal_list_explicit(self) bool

Check if this Interface node has an explicit formal list

stmts(self) Iterator[AstNode]

Get the statements for this Interface node

class chapel.IteratorType

A Chapel IteratorType AST node

class chapel.Label

A Chapel Label AST node

loop(self) Loop

Get the loop this Label node is attached to

name(self) str

Get the name of this Label node

class chapel.Let

A Chapel Let AST node

class chapel.Literal

A Chapel Literal AST node

class chapel.Local

A Chapel Local AST node

condition(self) Optional[AstNode]

Get the condition of this Local node

class chapel.Location

An object that represents the location of an AST node in a source file.

clamp_left(self, arg0: Location) Location

Get a new Location removes the left part of the current Location based on another Location

end(self) Tuple[int, int]

Get the line-column pair where this Location ends

path(self) str

Get the file path of this Location

start(self) Tuple[int, int]

Get the line-column pair where this Location starts

class chapel.Loop

A Chapel Loop AST node

block_style(self) str

Get the block style of this Loop node

body(self) AstNode

Get the body of this Loop node

header_location(self) Optional[Location]

Get the Location of this Loop node’s header

class chapel.LoopExprIteratorType

A Chapel LoopExprIteratorType AST node

class chapel.Manage

A Chapel Manage AST node

managers(self) Iterator[AstNode]

Get the managers of this Manage node

class chapel.ManageableType

A Chapel ManageableType AST node

class chapel.Module

A Chapel Module AST node

kind(self) str

Get the kind of this Module node

class chapel.MostSpecificCandidate

A candidate function returned from call resolution that represents the most specific overload matching the call.

formal_actual_mapping(self) List[int]

Get the index of the function’s formal for each of the call’s actuals.

function(self) TypedSignature

Get the signature of the function called by this candidate.

class chapel.MultiDecl

A Chapel MultiDecl AST node

class chapel.NamedDecl

A Chapel NamedDecl AST node

header_location(self) Optional[Location]

Get the Location of this NamedDecl node’s header

name(self) str

Get the name of this NamedDecl node

name_location(self) Location

Get the textual location of the NamedDecl node’s name

class chapel.New

A Chapel New AST node

management(self) str

Get the management style for this New node

type_expression(self) AstNode

Get the type expression for this New node

class chapel.NilType

A Chapel NilType AST node

class chapel.NoneParam

A Chapel NoneParam AST node

class chapel.NothingType

A Chapel NothingType AST node

class chapel.On

A Chapel On AST node

destination(self) AstNode

Get the destination of this On node

class chapel.OpCall

A Chapel OpCall AST node

is_binary_op(self) bool

Check if this OpCall node is a binary op

is_unary_op(self) bool

Check if this OpCall node is an unary op

op(self) str

Get the op string for this OpCall node

class chapel.OpaqueType

A Chapel OpaqueType AST node

class chapel.Param

The base type of Chapel parameters (compile-time known values)

class chapel.PrimCall

A Chapel PrimCall AST node

prim(self) str

Get the primitive name for this PrimCall node

class chapel.PrimitiveType

A Chapel PrimitiveType AST node

class chapel.PromotionIteratorType

A Chapel PromotionIteratorType AST node

class chapel.PtrType

A Chapel PtrType AST node

class chapel.Range

A Chapel Range AST node

lower_bound(self) Optional[AstNode]

Get the lower bound of this Range node

op_kind(self) str

Get the op kind of this Range node

upper_bound(self) Optional[AstNode]

Get the upper bound of this Range node

class chapel.RealLiteral

A Chapel RealLiteral AST node

text(self) str

Get the value of this RealLiteral node

class chapel.RealParam

A Chapel RealParam AST node

class chapel.RealType

A Chapel RealType AST node

class chapel.Record

A Chapel Record AST node

class chapel.RecordType

A Chapel RecordType AST node

class chapel.Reduce

A Chapel Reduce AST node

iterand(self) AstNode

Get the iterand for this Reduce node

op(self) AstNode

Get the op for this Reduce node

class chapel.ReduceIntent

A Chapel ReduceIntent AST node

op(self) AstNode

Get the op for this ReduceIntent node

class chapel.Require

A Chapel Require AST node

exprs(self) Iterator[AstNode]

Get the expressions of this Require node

class chapel.ResolvedExpression

Container for type information about a particular AST node.

most_specific_candidate(self) Optional[MostSpecificCandidate]

If this node is a call, return the most specific overload selected by call resolution.

type(self) Optional[Tuple[str, Optional[ChapelType], Optional[Param]]]

Retrieve the type of the expression.

class chapel.Return

A Chapel Return AST node

value(self) Optional[AstNode]

Get the expression returned by this Return node

class chapel.Scan

A Chapel Scan AST node

iterand(self) AstNode

Get the iterand for this Scan node

op(self) AstNode

Get the op for this Scan node

class chapel.Scope

A scope in the Chapel program, such as a block.

modules_named_in_use_or_import(self) List[Module]

Get the modules that were named in use or import statements directly within this scope

parent_scope(self) Optional[Scope]

Get the parent (outer) scope of this scope

visible_nodes(self) List[Tuple[str, List[AstNode]]]

Get the nodes corresponding to declarations exported from this scope

class chapel.Select

A Chapel Select AST node

exprs(self) AstNode

Get the expression of this Select node

when_stmts(self) Iterator[When]

Get the When statements of this Select node

class chapel.Serial

A Chapel Serial AST node

condition(self) Optional[AstNode]

Get the condition of this Serial node

class chapel.SimpleBlockLike

A Chapel SimpleBlockLike AST node

block_style(self) str

Get the block style of this SimpleBlockLike node

stmts(self) Iterator[AstNode]

Get the statements contained in this SimpleBlockLike.

class chapel.StringLikeLiteral

A Chapel StringLikeLiteral AST node

value(self) str

Get the value of this StringLikeLiteral node

class chapel.StringLiteral

A Chapel StringLiteral AST node

class chapel.StringParam

A Chapel StringParam AST node

value(self) str

Get the value of this string Param

class chapel.Sync

A Chapel Sync AST node

class chapel.SyncAuxType

A Chapel SyncAuxType AST node

class chapel.TaskIdType

A Chapel TaskIdType AST node

class chapel.TaskVar

A Chapel TaskVar AST node

class chapel.Throw

A Chapel Throw AST node

error_expression(self) AstNode

Get the expression thrown by this Throw node

class chapel.Try

A Chapel Try AST node

body(self) Block

Get the body of this Try node

handlers(self) Iterator[Catch]

Get the Catch node handlers of this Try node

is_expression_level(self) bool

Check if this Try node is expression level

is_try_bang(self) bool

Check if this Try node is a ‘try!’

class chapel.Tuple

A Chapel Tuple AST node

class chapel.TupleDecl

A Chapel TupleDecl AST node

decls(self) Iterator[Decl]

Get the declarations for this TupleDecl node

init_expression(self) Optional[AstNode]

Get the init expression of this TupleDecl node

intent_or_kind(self) str

Get the intent or kind of this TupleDecl node

type_expression(self) Optional[AstNode]

Get the type expression of this TupleDecl node

class chapel.TupleType

A Chapel TupleType AST node

class chapel.TypeDecl

A Chapel TypeDecl AST node

class chapel.TypeQuery

A Chapel TypeQuery AST node

class chapel.TypedSignature

The signature of a particular function. Could include types gathered when instantiating the function

ast(self) Optional[AstNode]

Get the AST from which this function signature is computed

formal_type(self, arg0: int) Optional[Tuple[str, Optional[ChapelType], Optional[Param]]]

Get the type of the nth formal of this function signature

is_instantiation(self) bool

Check if this function is an instantiation of a generic function

class chapel.UintLiteral

A Chapel UintLiteral AST node

text(self) str

Get the value of this UintLiteral node

class chapel.UintParam

A Chapel UintParam AST node

class chapel.UintType

A Chapel UintType AST node

class chapel.Union

A Chapel Union AST node

class chapel.UnionType

A Chapel UnionType AST node

class chapel.UnknownType

A Chapel UnknownType AST node

class chapel.Use

A Chapel Use AST node

visibility(self) str

Get the visibility of this Use node

visibility_clauses(self) Iterator[VisibilityClause]

Get the visibility clauses of this Use node

class chapel.VarArgFormal

A Chapel VarArgFormal AST node

count(self) Optional[AstNode]

Get the count expression of this VarArgFormal node

class chapel.VarLikeDecl

A Chapel VarLikeDecl AST node

init_expression(self) Optional[AstNode]

Get the init expression of this VarLikeDecl node

intent(self) str

Get the intent for this VarLikeDecl node

storage_kind(self) str

Get the storage kind of this VarLikeDecl node

type_expression(self) Optional[AstNode]

Get the type expression of this VarLikeDecl node

class chapel.Variable

A Chapel Variable AST node

is_config(self) bool

Check if this Variable node is a config variable

is_field(self) bool

Check if this Variable node is a class field variable

kind(self) str

Get the kind of this Variable node

class chapel.VisibilityClause

A Chapel VisibilityClause AST node

limitation_kind(self) str

Get the limitation kind of this VisibilityClause node

limitations(self) Iterator[AstNode]

Get the limitations of this VisibilityClause node

symbol(self) AstNode

Get the symbol referenced by this VisibilityClause node

class chapel.VoidType

A Chapel VoidType AST node

class chapel.When

A Chapel When AST node

block_style(self) str

Get the block style of this When node

body(self) Block

Get the body of this When node

case_exprs(self) Iterator[AstNode]

Get the case expressions of this When node

is_otherwise(self) bool

Check if this When node uses the otherwise keyword

class chapel.While

A Chapel While AST node

condition(self) AstNode

Get the condition of this While node

class chapel.WithClause

A Chapel WithClause AST node

exprs(self) Iterator[AstNode]

Get the expressions of this WithClause node

class chapel.Yield

A Chapel Yield AST node

value(self) Optional[AstNode]

Get the expression yielded by this Yield node

class chapel.Zip

A Chapel Zip AST node

Visitor

This module contains utilities for defining and using visitors for chapel.AstNode hierarchies.

chapel.visitor.enter(method)

Annotates a class method as being an ‘enter’ function. An ‘enter’ function is called on a node before its children are visited. If it returns a boolean, this boolean is used to determine whether or not the children are visited. Returning ‘False’ indicates that children should be skipped; returning ‘True’ indicates that children should be visited.

The ‘exit’ function is always called, even if the children were not visited.

chapel.visitor.exit(method)

Annotates a class method as being an ‘exit’ function. An ‘exit’ function is called after a node’s children were (or would have been) visited.

chapel.visitor.visitor(clazz)

Marks a class as being a visitor. This will add a ‘visit’ method to the class (overriding one if it exists), which can be used to recursively traverse an AST. The behavior of the ‘visit’ method is controlled via other methods defined on the class, particularly those annotated with @enter and @exit.

The traversal proceeds by means of ‘enter’ and ‘exit’ functions; see the documentation for those functions for more information. Enter and exit functions are both expected to take a single argument in addition to ‘self’: the node type being visited. A type annotation is required, and is used to determine what type of node the function should operate on.

Replace Utilities

A set of utilities for performing search-and-replace operations on Chapel code, informed by Chapel’s AST.

class chapel.replace.ReplacementContext(path: str)

This class is given as an argument to ‘finder’ functions so that they are able to retrieve information about the nodes and the current file. While Dyno parses the file and reports locations using line and column numbers, it does not have mappings from lines and columns to offsets in the file (which is what we need to read text). This class contains that information.

loc_to_idx(loc: Tuple[int, int]) int

Given a location (as retrieved from an AST node), convert this location into an offset in the source file.

node_idx_range(node: AstNode) Tuple[int, int]

Given a node, determine where it starts and ends in the given source file.

node_exact_string(node: AstNode) str

Return the substring that corresponds to the given node in the source file.

node_indent(node: AstNode) int

Determine the number of characters between the given node and the beginning of the line.

chapel.replace.rename_formals(rc: ReplacementContext, fn: Function, renames: Dict[str, str])

Helper iterator to be used in finder functions. Given a function and a map of (‘original formal name’ -> ‘new formal name’), yields updates that perform the formal renaming.

chapel.replace.rename_named_actuals(rc: ReplacementContext, call: Call, renames: Dict[str, str])

Helper iterator to be used in finder functions. Given a function call expression, and a map of (‘original name’ -> ‘new name’), yields updates that rename named actuals like the x in f(x=…).

chapel.replace.replace(finder: Generator, ctx: Context, filename: str) str

Drives replacement of text based on matches found in finder.

chapel.replace.run(finder: Generator, name: str = 'replace', description: str = 'A tool to search-and-replace Chapel expressions with others')

Start a command-line replacer program with the given ‘finder’ function. This program will automatically support accepting a list of files on the command line, and two command-line options.

The first option is ‘–suffix’, used for out-of-place substitutions: the new file will be called ‘.chpl.thesuffix’. The default suffix value is ‘new’.

The second option is ‘–in-place’, used to perform in-place (modifying) substitutions on files.

chapel.replace.fuse(*args)

Combines multiple ‘finder’ iterators into one.

LSP Utilities

This module contains utility functions for working with Chapel compiler types and the Language Server Protocol.

chapel.lsp.location_to_range(location) Range

Convert a Chapel location into a lsprotocol.types Range, which is used for e.g. reporting diagnostics.

chapel.lsp.error_to_diagnostic(error) Diagnostic

Convert a Chapel error into a lsprotocol.types Diagnostic