Skip to documentation
SLOP

tiny.python.syntax.ast

Reference tiny.python syntax ast

Defined in syntax.

A Python program in the package's subset parses into a syntax tree.

API (31)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callssyntaxast
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Source: lib/python/src/syntax/ast.zig

zig
//! A Python program in the package's subset parses into a syntax tree. The program is a list of//! statements. Statements hold expressions and nested lists of statements. Each expression is a//! tree of operators and operands.//!//! The compiler walks the tree once to emit instructions, so every construct of the subset needs a//! node shape of its own that the compiler can tell apart. A program's tree has many small nodes,//! and all of them are freed together when the caller is done with the program.//!//! One tagged union, `Statement`, has a tag for each kind of statement. A second tagged union,//! `Expression`, has a tag for each kind of expression. So the compiler's switch over a node covers//! every construct. A child expression is a pointer to a constant node. A list of children is a//! constant slice. The parsed program, `Program`, owns one arena that holds every node and list.//! Names and string contents are slices of the source text, so the text has to outlive the tree.//!//! The `else` branch of `if`, `while` and `for` is a field named `otherwise`. When the source has//! no `else`, that field is empty. An `elif` is stored as an `if` statement that is the only//! statement of the previous `if`'s `otherwise` list.const std = @import("std");/// The syntax tree of one program: its top-level statements and the arena that holds every node./// `parse` builds it and `compile` reads it. The caller frees it with `deinit`.pub const Program = struct {    /// The arena allocator that holds every statement, expression and list of the tree. `parse`    /// creates it on the caller's allocator. `deinit` frees it.    arena: std.heap.ArenaAllocator,    /// The program's top-level statements in source order, allocated in the arena.    statements: []const Statement,    /// Frees every node of the tree at once by freeing the arena. The package's `execute` calls it    /// as it returns, after the bytecode compiled from the tree is freed. The call leaves the    /// program undefined. Every slice taken from the tree's lists is invalid afterward. The    /// bytecode that `compile` builds borrows each function's parameter list from the arena, so the    /// tree has to outlive that bytecode. The source text stays the caller's, and `deinit` leaves    /// it alone.    pub fn deinit(self: *Program) void {        self.arena.deinit();        self.* = undefined;    }};/// One statement of the subset, as a tagged union with one tag per kind of statement. The compiler/// switches on its tag to emit each statement's instructions. `parse` builds one for each statement/// of the program.pub const Statement = union(enum) {    /// An expression statement: an expression evaluated for its value. At the top level, the value    /// of the last one run becomes the program's result. Inside a function, the value is dropped.    expression: *const Expression,    /// An assignment to one name, such as `x = 1`.    assign: Assign,    /// An assignment to one item selected by an index, such as `xs[0] = 2`.    subscript_assign: SubscriptAssign,    /// A `del` statement for one name or one item selected by an index.    delete: Delete,    /// A `break` statement. The compiler rejects one outside a loop.    break_stmt,    /// A `continue` statement. The compiler rejects one outside a loop.    continue_stmt,    /// A `def` statement. The compiler accepts one at the top level alone.    function: Function,    /// A `for` loop.    for_stmt: ForStatement,    /// An `if` statement, whose `elif` and `else` parts are stored in its `otherwise` list.    if_stmt: IfStatement,    /// A `pass` statement, which the compiler skips.    pass,    /// A `return` statement, with or without a value. The compiler rejects one at the top level.    return_stmt: Return,    /// A `while` loop.    while_stmt: WhileStatement,};/// An assignment of a value to one name. The compiler turns one into a store to the name. The/// target is a single name. `a, b = 1, 2` fails to parse with `UnexpectedToken`, because its left/// side is a tuple.pub const Assign = struct {    /// The assigned name, a slice of the source text.    name: []const u8,    /// The expression whose value is assigned.    value: *const Expression,};/// An assignment to one item selected by an index, such as `xs[0] = 2` or `d["k"] = v`. The/// compiler turns one into a store into a list or dictionary. A slice is never a target, so/// `xs[0:1] = [2]` fails to parse with `UnexpectedToken`.pub const SubscriptAssign = struct {    /// The expression before the brackets, which gives the container.    target: *const Expression,    /// The expression inside the brackets.    index: *const Expression,    /// The expression whose value is stored.    value: *const Expression,};/// The target of a `del` statement: one name, or one item selected by an index. The compiler turns/// one into the removal of a name or of an item. A `del` takes one target. For any other target, a/// slice included, parsing fails with `UnexpectedToken`.pub const Delete = union(enum) {    /// The name to remove, a slice of the source text.    name: []const u8,    /// The item to remove from a container.    subscript: SubscriptDelete,};/// The item a `del` removes: a container and an index. The compiler turns one, as in `del xs[0]`,/// into the removal of that item.pub const SubscriptDelete = struct {    /// The expression before the brackets, which gives the container.    target: *const Expression,    /// The expression inside the brackets.    index: *const Expression,};/// A function definition: its name, its parameter names and its body. The compiler turns each one/// into a separate block of bytecode bound to the function's name. Each parameter is a plain name./// A trailing comma after the last parameter is allowed.pub const Function = struct {    /// The function's name, a slice of the source text.    name: []const u8,    /// The parameter names in order, each a slice of the source text. For a function without    /// parameters, the list is empty.    params: []const []const u8,    /// The statements of the function's body in order.    body: []const Statement,};/// A `for` loop: the loop's name, the expression it takes items from, the body, and the `else`/// branch. The compiler turns one into a loop that takes one item per pass from a list, tuple,/// string, range, dictionary or iterator. The loop's target is one name.pub const ForStatement = struct {    /// The name bound to each item in turn, a slice of the source text.    name: []const u8,    /// The expression that gives the items. The iterable is one expression with no bare comma, so    /// `for x in 1, 2:` fails to parse.    iterable: *const Expression,    /// The statements run for each item.    body: []const Statement,    /// The statements of the `else` branch. The branch runs once the loop has taken every item.    /// When `break` ends the loop, the branch is skipped. When the loop has no `else`, the list is    /// empty.    otherwise: []const Statement,};/// An `if` statement: its condition, the body run when the condition is true, and the `else`/// branch. The compiler turns one into a test of the condition and a jump over the branch that does/// not run.pub const IfStatement = struct {    /// The expression tested for truth. The condition is one expression with no bare comma.    condition: *const Expression,    /// The statements run when the condition is true.    body: []const Statement,    /// The statements run when the condition is false. For an `elif`, the list holds one `if`    /// statement for the `elif` and its own branches. For an `else`, the list holds the `else`    /// body. Without either, the list is empty.    otherwise: []const Statement,};/// A `return` statement and its optional value. The compiler turns one into leaving the function/// with a value.pub const Return = struct {    /// The returned expression. For a bare `return`, the field is `null`. A bare `return` returns    /// `None`.    value: ?*const Expression,};/// A `while` loop: its condition, its body and its `else` branch. The compiler turns one into a/// test at the top of each pass and a jump back.pub const WhileStatement = struct {    /// The expression tested for truth before each pass. The condition is one expression with no    /// bare comma.    condition: *const Expression,    /// The statements run on each pass while the condition is true.    body: []const Statement,    /// The statements of the `else` branch. The branch runs once the condition is false. When    /// `break` ends the loop, the branch is skipped. When the loop has no `else`, the list is    /// empty.    otherwise: []const Statement,};/// One expression, as a tagged union with one tag per kind of expression. The compiler switches on/// its tag to emit the instructions that compute each value. `parse` allocates each node in the/// program's arena. A node points to its children as constant nodes.pub const Expression = union(enum) {    /// The literal `None`.    none,    /// The literal `True` or `False`.    boolean: bool,    /// The value of an integer literal, as a signed 128-bit integer. The literal has no sign, so    /// `-5` is unary minus applied to 5.    integer: i128,    /// The contents of a string literal: the bytes between the quotes, as a slice of the source    /// text. A backslash stays in the bytes as written, with no escape decoding.    string: []const u8,    /// A name to look up, as a slice of the source text.    name: []const u8,    /// Unary minus or `not` applied to one operand.    unary: Unary,    /// `+`, `-` or `*` applied to two operands.    binary: Binary,    /// A chain of one or more comparisons, such as `a < b <= c`.    comparison: Comparison,    /// `and` or `or` applied to two operands.    logical: Logical,    /// A call of a function or method with its arguments.    call: Call,    /// An attribute access, such as `xs.append`.    attribute: Attribute,    /// A list display, such as `[1, x]`.    list: List,    /// A tuple: expressions separated by commas, or `()` for the empty tuple.    tuple: Tuple,    /// A dictionary display, such as `{"a": 1}`.    dict: Dict,    /// An index or a slice applied to a value, such as `xs[0]` or `xs[1:3]`.    subscript: Subscript,};/// An operator applied to one operand. The compiler emits the operand's instructions and then one/// instruction for the operator.pub const Unary = struct {    /// Which operator: unary minus or `not`.    op: UnaryOp,    /// The operand.    operand: *const Expression,};/// The two unary operators of the subset. The compiler picks the instruction for a `Unary` node/// from it. The parser binds `not` more loosely than comparisons. The parser binds unary minus more/// tightly than `*`.pub const UnaryOp = enum {    /// Unary minus, as in `-x`. Negating the smallest 128-bit integer fails with `IntegerOverflow`    /// when the program runs.    negate,    /// `not`, which gives `True` when its operand is false and `False` otherwise.    not,};/// An arithmetic operator applied to two operands. The compiler emits both operands' instructions,/// left first, and then one instruction for the operator. Operators of one precedence level group/// from the left, so `1 - 2 - 3` is `(1 - 2) - 3`.pub const Binary = struct {    /// Which operator.    op: BinaryOp,    /// The left operand, evaluated first.    left: *const Expression,    /// The right operand.    right: *const Expression,};/// The three arithmetic operators of the subset: `+`, `-` and `*`. The compiler picks the/// instruction for a `Binary` node from it. Integer results past the signed 128-bit range fail with/// `IntegerOverflow` when the program runs.pub const BinaryOp = enum {    /// `+`: integer addition, or joining two strings, two lists or two tuples.    add,    /// `-`: integer subtraction.    sub,    /// `*`: integer multiplication, or a string, list or tuple repeated an integer number of times.    /// The count can stand on either side of `*`.    mul,};/// A chain of comparisons: a first operand, then each operator with its right operand. The compiler/// turns one chain into pairwise tests that stop at the first false one. `a < b < c` tests `a < b`/// and then `b < c`. Each operand is evaluated once. The parser builds one only when at least one/// operator follows the first operand.pub const Comparison = struct {    /// The first operand of the chain.    left: *const Expression,    /// Each operator with its right operand, in source order. The slice holds at least one.    terms: []const ComparisonTerm,};/// One operator of a comparison chain with the operand to its right. A `Comparison` holds one per/// operator of the chain. For the first term, the left operand is the chain's first operand. For/// every later term, the left operand is the previous term's right operand.pub const ComparisonTerm = struct {    /// The comparison operator.    op: ComparisonOp,    /// The operand to the right of the operator.    right: *const Expression,};/// The ten comparison operators of the subset. The compiler maps each tag to one comparison/// instruction.pub const ComparisonOp = enum {    /// `==`.    equal,    /// `!=`.    not_equal,    /// `<`.    less,    /// `<=`.    less_equal,    /// `>`.    greater,    /// `>=`.    greater_equal,    /// `in`, a membership test: true when the right operand holds the left operand.    contains,    /// `not in`, the negated membership test.    not_contains,    /// `is`, an identity test.    identical,    /// `is not`, the negated identity test.    not_identical,};/// `and` or `or` applied to two operands. The compiler turns one into a test of the left operand/// and a jump past the right one. The right operand is evaluated only when the left one does not/// decide the result. The result is the deciding operand's own value, so `0 and x` gives 0 and/// `None or 9` gives 9. A chain such as `a or b or c` groups from the left.pub const Logical = struct {    /// Which operator.    op: LogicalOp,    /// The left operand, always evaluated.    left: *const Expression,    /// The right operand, evaluated only when the left one does not decide the result.    right: *const Expression,};/// The two operators that evaluate their right operand only when needed. The compiler picks the/// jump pattern for a `Logical` node from it.pub const LogicalOp = enum {    /// `and`: gives the left operand when it is false, and otherwise gives the right operand.    and_op,    /// `or`: gives the left operand when it is true, and otherwise gives the right operand.    or_op,};/// A call: the called value and its arguments. The compiler emits the called value, then each/// argument in order, then one call instruction with the argument count. Each argument is one/// expression passed by position. A trailing comma after the last argument is allowed.pub const Call = struct {    /// The expression that gives the function or method to call.    target: *const Expression,    /// The argument expressions in order. For a call without arguments, the list is empty.    arguments: []const *const Expression,};/// An attribute access: a value and the name after the dot. The compiler turns one into an/// instruction that looks the name up on the value, so a method call such as `xs.append(1)` finds/// its method. When the program runs, the name resolves to one of the methods of a list or/// dictionary.pub const Attribute = struct {    /// The expression before the dot.    target: *const Expression,    /// The name after the dot, as a slice of the source text.    name: []const u8,};/// A list display: the item expressions between `[` and `]`. The compiler emits each item and then/// one instruction that builds a list of that many items.pub const List = struct {    /// The item expressions in order. For `[]`, the list is empty. A trailing comma after the last    /// item is allowed.    items: []const *const Expression,};/// A tuple: expressions separated by commas, or `()` for the empty tuple. The compiler emits each/// item and then one instruction that builds a tuple of that many items. Parentheses around one/// expression with no comma only group it. `(1,)` is a tuple of one item.pub const Tuple = struct {    /// The item expressions in order. For `()`, the list is empty.    items: []const *const Expression,};/// A dictionary display: the key and value pairs between `{` and `}`. The compiler emits each key/// and value in order and then one instruction that builds a dictionary of that many entries.pub const Dict = struct {    /// The entries in source order. For `{}`, the list is empty. A trailing comma after the last    /// entry is allowed. When a key repeats, the later value replaces the earlier one at run time.    items: []const DictItem,};/// One entry of a dictionary display: a key expression and a value expression. A `Dict` holds one/// per entry of the display.pub const DictItem = struct {    /// The key expression, before the `:`.    key: *const Expression,    /// The value expression, after the `:`.    value: *const Expression,};/// A value followed by brackets that hold one index or a slice. The compiler emits the value, then/// the index or the three slice bounds, then one instruction that reads the item or the slice.pub const Subscript = struct {    /// The expression before the brackets.    target: *const Expression,    /// What the brackets hold: one index or a slice.    selector: SubscriptSelector,};/// The contents of a subscript's brackets: one index expression or a slice. The compiler emits an/// index read or a slice read depending on its tag. A colon inside the brackets makes it a slice. A/// comma inside the brackets fails to parse with `ExpectedRightBracket`.pub const SubscriptSelector = union(enum) {    /// The index expression, as in `xs[0]`.    index: *const Expression,    /// A slice, as in `xs[1:3]`.    slice: Slice,};/// The three bounds of a slice, each optional. A `SubscriptSelector` holds one for a subscript with/// a colon. A bound left out is `null`, so every bound of `xs[:]` is `null`. The compiler passes/// `None` for each bound left out.pub const Slice = struct {    /// The index of the first item taken. When the start is left out, as in `xs[:2]`, the field is    /// `null`.    start: ?*const Expression,    /// The index the slice stops before. When the stop is left out, as in `xs[1:]`, the field is    /// `null`.    stop: ?*const Expression,    /// The distance between the indexes taken. When the step is left out, as in `xs[1:3]` or    /// `xs[1:3:]`, the field is `null`.    step: ?*const Expression,};test "expression tags are stable" {    const value = Expression{ .integer = 7 };    try std.testing.expectEqual(@as(i128, 7), value.integer);}

Source: lib/python/src/syntax/root.zig:10

zig
pub const ast = @import("ast.zig");

Audit

Definitions32
Public names36
Members97
Version26.7.0
Revisiondaab053ee433