lib/python/src/code/op.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 //! The package's virtual machine has 39 operations, each of which takes its inputs from one stack
  2 //! of values and pushes its result back onto it. Each operation has to be small enough for the
  3 //! virtual machine to run with one switch, and together they have to express every statement and
  4 //! expression that the package accepts from Python 3.14, including `and` and `or`, chained
  5 //! comparisons, loops with `else` blocks, and calls.
  6 //!
  7 //! Instructions run in order from one list, so every `if`, loop, `and` and `or` has to become jumps
  8 //! within that list. Python evaluates `a < b < c` with `b` computed once and stops at the first
  9 //! false comparison, so the middle operand has to stay available while its first comparison runs.
 10 //!
 11 //! The package keeps the stack-machine design of [CPython](https://github.com/python/cpython):
 12 //! values move through one stack, and each operation pops its inputs and pushes its result.
 13 //!
 14 //! Each tag takes at most one integer operand, which the instruction stores. Each tag's doc below
 15 //! says what the operation pops, what it pushes and what its operand means. A jump names an
 16 //! absolute position in the chunk's list of instructions. `jump_if_false` leaves the tested value
 17 //! on the stack, so `and` and `or` can return the operand that decided them. The compiler emits a
 18 //! `pop` on each path that no longer needs the tested value. A chained comparison uses `dup`,
 19 //! `rotate_three` and `swap` to keep each middle operand for the comparison after it. A function
 20 //! body ends with `return_value`. The top level ends with `ret`, which returns the value that
 21 //! `save` last recorded from a top-level expression statement.
 22 /// The operations of the package's bytecode, one tag each. The compiler picks one tag per
 23 /// instruction, and the virtual machine's run loop switches on it. An instruction carries the tag
 24 /// with one integer operand, and each tag's doc says what the operand means. The virtual machine
 25 /// checks the stack depth before each operation that pops, and fails with `StackUnderflow` when too
 26 /// few values are there.
 27 pub const Op = enum {
 28     /// Pushes the constant at the operand's position in the current chunk's constant table.
 29     constant,
 30     /// Pushes the value of the name at the operand's position in the current chunk's name table.
 31     /// The lookup tries the current call's local variables, then the global variables, then the
 32     /// builtin functions. The lookup fails with `UndefinedName` when none of the three holds the
 33     /// name.
 34     load,
 35     /// Pops a value and binds it to the name at the operand's position. At top level the binding is
 36     /// a global variable, and inside a call it is a local variable of that call.
 37     store,
 38     /// Removes the binding of the name at the operand's position: a global variable at top level,
 39     /// and a local variable of the call inside a function. The operation fails with `UndefinedName`
 40     /// when the name has no binding there. The operation leaves the stack as it was. The compiler
 41     /// emits it for `del name`.
 42     delete,
 43     /// Pops the top value and discards it. The compiler emits it after an expression statement
 44     /// inside a function, after each condition test, and to drop the iterators of loops that
 45     /// `break` or `return` leaves.
 46     pop,
 47     /// Pops the top value and records it in the current frame. `ret` later returns the recorded
 48     /// value. The compiler emits it after each expression statement at top level, so a program's
 49     /// value is the value of its last top-level expression statement.
 50     save,
 51     /// Pushes a second copy of the top value. The compiler emits it in a chained comparison to keep
 52     /// a middle operand.
 53     dup,
 54     /// Exchanges the top two values. When a chained comparison stops early, the compiler emits it
 55     /// to bring the kept middle operand above the false result, and a `pop` then drops that
 56     /// operand.
 57     swap,
 58     /// Moves the top value below the two values under it, so the stack `a b c`, with `c` on top,
 59     /// becomes `c a b`. In a chained comparison, the operation moves the copy of the middle operand
 60     /// below the two values being compared.
 61     rotate_three,
 62     /// Continues at the instruction whose position is the operand. The operation leaves the stack
 63     /// as it was.
 64     jump,
 65     /// Continues at the operand's position when the top value is false by Python's truth rules, and
 66     /// at the next instruction otherwise. The operation leaves the tested value on the stack on
 67     /// both paths. The compiler follows it with `pop` on each path that no longer needs the value,
 68     /// so `and` and `or` return the operand that decided them.
 69     jump_if_false,
 70     /// Pops two values, with the right operand on top, and pushes their sum. Integers and booleans
 71     /// add as integers, and two lists, two tuples or two strings join into a new object on the
 72     /// heap. The operation fails with `IntegerOverflow` when the sum leaves the signed 128-bit
 73     /// range, and with `TypeError` for any other pair of types.
 74     add,
 75     /// Pops two integers or booleans and pushes the left minus the right. The operation fails with
 76     /// `IntegerOverflow` when the result leaves the signed 128-bit range, and with `TypeError` for
 77     /// any other type.
 78     sub,
 79     /// Pops two values and pushes their product. Integers and booleans multiply as integers, and a
 80     /// list, tuple or string on either side of an integer or boolean repeats into a new object on
 81     /// the heap. A count of zero or less gives an empty sequence. The operation fails with
 82     /// `IntegerOverflow` when the product or the repeated length overflows, and with `TypeError`
 83     /// for any other pair of types.
 84     mul,
 85     /// Pops an integer or boolean and pushes its negation as an integer. The operation fails with
 86     /// `IntegerOverflow` for the smallest signed 128-bit integer, and with `TypeError` for any
 87     /// other type.
 88     neg,
 89     /// Pops a value and pushes `True` when the value is false by Python's truth rules, and `False`
 90     /// otherwise.
 91     not,
 92     /// Pops two values and pushes whether they are equal, as `Value.eql` decides. Values of
 93     /// unrelated types compare unequal, and the comparison returns no error.
 94     equal,
 95     /// Pops two values and pushes whether they are unequal, the negation of `equal`.
 96     not_equal,
 97     /// Pops two values and pushes whether the left is less than the right. Integers and booleans
 98     /// compare as numbers, strings compare by their UTF-8 bytes, and lists and tuples compare item
 99     /// by item. When one list or tuple is a prefix of the other, the shorter one is less. The
100     /// operation fails with `TypeError` for any other pair of types, including a list against a
101     /// tuple.
102     less,
103     /// Pops two values and pushes whether the left is less than or equal to the right, under the
104     /// ordering that `less` uses. The operation fails with `TypeError` for the pairs of types that
105     /// `less` rejects.
106     less_equal,
107     /// Pops two values and pushes whether the left is greater than the right, under the ordering
108     /// that `less` uses. The operation fails with `TypeError` for the pairs of types that `less`
109     /// rejects.
110     greater,
111     /// Pops two values and pushes whether the left is greater than or equal to the right, under the
112     /// ordering that `less` uses. The operation fails with `TypeError` for the pairs of types that
113     /// `less` rejects.
114     greater_equal,
115     /// Pops a container from the top, then an item, and pushes whether the item is in the
116     /// container, so `x in xs` pushes `x` first. A list or tuple matches an item that is the same
117     /// object or equal. A dictionary or its keys view tests its keys, a values view tests its
118     /// values, and an items view tests a two-item tuple against a key and its value. A range tests
119     /// membership from its start, stop and step, in constant time. A string tests for a substring.
120     /// An iterator takes items until one matches, so the items it passed are gone. The operation
121     /// fails with `TypeError` for an unhashable item tested against a dictionary or its keys, for
122     /// an item other than a string tested against a string, and for a container of any other type.
123     contains,
124     /// Pops a container from the top, then an item, and pushes whether the item is absent from the
125     /// container, under the rules of `contains`.
126     not_contains,
127     /// Pops two values and pushes whether they are the same object. `None`, booleans and integers
128     /// are the same when their values are. A boolean is never the same as an integer, although
129     /// `True == 1` holds. Two strings are the same when they start at the same address and have the
130     /// same length. Functions and builtins compare their positions and tags, and objects on the
131     /// heap compare their addresses.
132     identical,
133     /// Pops two values and pushes whether they are different objects, the negation of `identical`.
134     not_identical,
135     /// The operand is the number of arguments, which sit on top of the stack in order, with the
136     /// called value below them. A Python function takes the called value and the arguments off the
137     /// stack, binds each argument to its parameter in a new call frame, and runs the body, whose
138     /// `return_value` pushes the result. A builtin function or bound method runs at once and
139     /// replaces the called value and the arguments with its result. The operation fails with
140     /// `StackUnderflow` when the stack holds fewer values than the arguments and the called value,
141     /// with `ArityMismatch` when the number of arguments does not fit, with `InvalidFunction` when
142     /// a function value names no function, and with `TypeError` when the value cannot be called.
143     call,
144     /// Pops a list or dictionary and pushes its method, bound to that object and named by the
145     /// operand's position in the name table. Lists offer `append`, `clear`, `copy` and `pop`, and
146     /// dictionaries offer `clear`, `copy`, `get`, `items`, `keys`, `pop`, `popitem`, `setdefault`,
147     /// `update` and `values`. Each read creates a new bound method on the heap. The operation fails
148     /// with `AttributeError` for any other name and for any other type.
149     attribute,
150     /// Pops as many values as the operand says and pushes a new list of them, in the order they
151     /// were pushed. The operation fails with `StackUnderflow` when the stack holds fewer values.
152     build_list,
153     /// Pops as many values as the operand says and pushes a new tuple of them, in the order they
154     /// were pushed. The operation fails with `StackUnderflow` when the stack holds fewer values.
155     build_tuple,
156     /// The operand is the number of key and value pairs, and the stack holds each key followed by
157     /// its value. The operation pops all of them and pushes a new dictionary with the pairs in
158     /// stack order. A repeated key keeps its first position and takes the last value. The operation
159     /// fails with `TypeError` for an unhashable key, and with `IntegerOverflow` when twice the
160     /// operand overflows.
161     build_dict,
162     /// Pops a value and pushes an iterator over it. A list, tuple, range, string, dictionary or
163     /// dictionary view gets a new iterator on the heap, and a dictionary's iterator yields its
164     /// keys. An iterator goes back on the stack as it is. The operation fails with `TypeError` for
165     /// any other type.
166     iter,
167     /// The operand is the position of the first instruction after the loop body. The instruction
168     /// reads the iterator on top of the stack and pushes its next item above it. When the iterator
169     /// is exhausted, the operation pops it and continues at the operand's position. The operation
170     /// fails with `TypeError` when the top value is other than an iterator.
171     for_next,
172     /// Pops an index from the top, then a container, and pushes the item. A list or tuple takes an
173     /// integer or boolean index, counts a negative index from the end, and fails with `IndexError`
174     /// outside the sequence. A dictionary looks the key up and fails with `KeyError` when the key
175     /// is absent. The operation fails with `TypeError` for a sequence index other than an integer
176     /// or boolean, for an unhashable key, and for any other container, strings and ranges included.
177     subscript,
178     /// Pops the step, the stop and the start, then a container, and pushes the slice. The compiler
179     /// pushes `None` for each part the source leaves out. A list, tuple or string gives a new value
180     /// of the same type, and a range gives a new range. Strings are sliced by codepoint. A string
181     /// slice with step 1 points into the original bytes, and every other string slice is a copy on
182     /// the heap. The operation fails with `ValueError` for a step of zero or a string with invalid
183     /// UTF-8, and with `TypeError` for a bound other than an integer, boolean or `None`, and for
184     /// any other container.
185     slice,
186     /// Pops a value, an index and a container, and stores the value in the container at that index.
187     /// A list replaces the item at an integer or boolean index, counts a negative index from the
188     /// end, and fails with `IndexError` outside the list. A dictionary inserts the key or replaces
189     /// its value, and fails with `TypeError` when the key is unhashable. The operation fails with
190     /// `TypeError` for any other container, tuples included. The instruction pushes nothing.
191     store_subscript,
192     /// Pops an index from the top, then a container, and removes that item. A list removes the item
193     /// at the index and shifts the later items down, with the index rules and errors of
194     /// `subscript`. A dictionary removes the key, and fails with `KeyError` when the key is absent
195     /// and with `TypeError` when it is unhashable. The operation fails with `TypeError` for any
196     /// other container.
197     delete_subscript,
198     /// Pops the return value, ends the current call and pushes the value for the caller. In the
199     /// top-level frame, the operation ends the run with that value. The compiler emits it for
200     /// `return` and at the end of every function body. Before a `return` inside loops, the compiler
201     /// pops the iterators of those loops.
202     return_value,
203     /// Ends the current frame with the value that `save` last recorded, or with `None` when no
204     /// expression statement ran. The compiler emits it once, at the end of the top-level chunk.
205     ret,
206 };