cpython/Python/codegen.c

/*
 * This file implements the compiler's code generation stage, which
 * produces a sequence of pseudo-instructions from an AST.
 *
 * The primary entry point is _PyCodegen_Body() for modules, and
 * _PyCodegen_Expression() for expressions.
 *
 * CAUTION: The VISIT_* macros abort the current function when they
 * encounter a problem. So don't invoke them when there is memory
 * which needs to be released. Code blocks are OK, as the compiler
 * structure takes care of releasing those.  Use the arena to manage
 * objects.
 */

#include <stdbool.h>

#include "Python.h"
#include "opcode.h"
#include "pycore_ast.h"           // _PyAST_GetDocString()
#define NEED_OPCODE_TABLES
#include "pycore_opcode_utils.h"
#undef NEED_OPCODE_TABLES
#include "pycore_compile.h"
#include "pycore_instruction_sequence.h" // _PyInstructionSequence_NewLabel()
#include "pycore_intrinsics.h"
#include "pycore_long.h"          // _PyLong_GetZero()
#include "pycore_object.h"        // _Py_ANNOTATE_FORMAT_VALUE_WITH_FAKE_GLOBALS
#include "pycore_pystate.h"       // _Py_GetConfig()
#include "pycore_symtable.h"      // PySTEntryObject

#define NEED_OPCODE_METADATA
#include "pycore_opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed
#undef NEED_OPCODE_METADATA

#define COMP_GENEXP
#define COMP_LISTCOMP
#define COMP_SETCOMP
#define COMP_DICTCOMP

/* A soft limit for stack use, to avoid excessive
 * memory use for large constants, etc.
 *
 * The value 30 is plucked out of thin air.
 * Code that could use more stack than this is
 * rare, so the exact value is unimportant.
 */
#define STACK_USE_GUIDELINE

#undef SUCCESS
#undef ERROR
#define SUCCESS
#define ERROR

#define RETURN_IF_ERROR(X)

#define RETURN_IF_ERROR_IN_SCOPE(C, CALL)

struct _PyCompiler;
compiler;

#define INSTR_SEQUENCE(C)
#define FUTURE_FEATURES(C)
#define SYMTABLE(C)
#define SYMTABLE_ENTRY(C)
#define OPTIMIZATION_LEVEL(C)
#define IS_INTERACTIVE_TOP_LEVEL(C)
#define SCOPE_TYPE(C)
#define QUALNAME(C)
#define METADATA(C)

instruction;
instr_sequence;
location;
jump_target_label;

fblockinfo;

#define LOCATION(LNO, END_LNO, COL, END_COL)

#define LOC(x)

#define NEW_JUMP_TARGET_LABEL(C, NAME)

#define USE_LABEL(C, LBL)

static const int compare_masks[] =;

/*
 * Resize the array if index is out of range.
 *
 * idx: the index we want to access
 * arr: pointer to the array
 * alloc: pointer to the capacity of the array
 * default_alloc: initial number of items
 * item_size: size of each item
 *
 */
int
_PyCompile_EnsureArrayLargeEnough(int idx, void **array, int *alloc,
                                  int default_alloc, size_t item_size)
{}


pattern_context;

static int codegen_nameop(compiler *, location, identifier, expr_context_ty);

static int codegen_visit_stmt(compiler *, stmt_ty);
static int codegen_visit_keyword(compiler *, keyword_ty);
static int codegen_visit_expr(compiler *, expr_ty);
static int codegen_augassign(compiler *, stmt_ty);
static int codegen_annassign(compiler *, stmt_ty);
static int codegen_subscript(compiler *, expr_ty);
static int codegen_slice_two_parts(compiler *, expr_ty);
static int codegen_slice(compiler *, expr_ty);

static bool are_all_items_const(asdl_expr_seq *, Py_ssize_t, Py_ssize_t);


static int codegen_with(compiler *, stmt_ty, int);
static int codegen_async_with(compiler *, stmt_ty, int);
static int codegen_async_for(compiler *, stmt_ty);
static int codegen_call_simple_kw_helper(compiler *c,
                                         location loc,
                                         asdl_keyword_seq *keywords,
                                         Py_ssize_t nkwelts);
static int codegen_call_helper_impl(compiler *c, location loc,
                                    int n, /* Args already pushed */
                                    asdl_expr_seq *args,
                                    PyObject *injected_arg,
                                    asdl_keyword_seq *keywords);
static int codegen_call_helper(compiler *c, location loc,
                               int n, asdl_expr_seq *args,
                               asdl_keyword_seq *keywords);
static int codegen_try_except(compiler *, stmt_ty);
static int codegen_try_star_except(compiler *, stmt_ty);

static int codegen_sync_comprehension_generator(
                                      compiler *c, location loc,
                                      asdl_comprehension_seq *generators, int gen_index,
                                      int depth,
                                      expr_ty elt, expr_ty val, int type,
                                      int iter_on_stack);

static int codegen_async_comprehension_generator(
                                      compiler *c, location loc,
                                      asdl_comprehension_seq *generators, int gen_index,
                                      int depth,
                                      expr_ty elt, expr_ty val, int type,
                                      int iter_on_stack);

static int codegen_pattern(compiler *, pattern_ty, pattern_context *);
static int codegen_match(compiler *, stmt_ty);
static int codegen_pattern_subpattern(compiler *,
                                      pattern_ty, pattern_context *);
static int codegen_make_closure(compiler *c, location loc,
                                PyCodeObject *co, Py_ssize_t flags);


/* Add an opcode with an integer argument */
static int
codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc)
{}

#define ADDOP_I(C, LOC, OP, O)

#define ADDOP_I_IN_SCOPE(C, LOC, OP, O)

static int
codegen_addop_noarg(instr_sequence *seq, int opcode, location loc)
{}

#define ADDOP(C, LOC, OP)

#define ADDOP_IN_SCOPE(C, LOC, OP)

static int
codegen_addop_load_const(compiler *c, location loc, PyObject *o)
{}

#define ADDOP_LOAD_CONST(C, LOC, O)

#define ADDOP_LOAD_CONST_IN_SCOPE(C, LOC, O)

/* Same as ADDOP_LOAD_CONST, but steals a reference. */
#define ADDOP_LOAD_CONST_NEW(C, LOC, O)

static int
codegen_addop_o(compiler *c, location loc,
                int opcode, PyObject *dict, PyObject *o)
{}

#define ADDOP_N(C, LOC, OP, O, TYPE)

#define ADDOP_N_IN_SCOPE(C, LOC, OP, O, TYPE)

#define LOAD_METHOD
#define LOAD_SUPER_METHOD
#define LOAD_ZERO_SUPER_ATTR
#define LOAD_ZERO_SUPER_METHOD

static int
codegen_addop_name(compiler *c, location loc,
                   int opcode, PyObject *dict, PyObject *o)
{}

#define ADDOP_NAME(C, LOC, OP, O, TYPE)

static int
codegen_addop_j(instr_sequence *seq, location loc,
                int opcode, jump_target_label target)
{}

#define ADDOP_JUMP(C, LOC, OP, O)

#define ADDOP_COMPARE(C, LOC, CMP)

#define ADDOP_BINARY(C, LOC, BINOP)

#define ADDOP_INPLACE(C, LOC, BINOP)

#define ADD_YIELD_FROM(C, LOC, await)

#define POP_EXCEPT_AND_RERAISE(C, LOC)

#define ADDOP_YIELD(C, LOC)

/* VISIT and VISIT_SEQ takes an ASDL type as their second argument.  They use
   the ASDL name to synthesize the name of the C type and the visit function.
*/

#define VISIT(C, TYPE, V)

#define VISIT_IN_SCOPE(C, TYPE, V)

#define VISIT_SEQ(C, TYPE, SEQ)

#define VISIT_SEQ_IN_SCOPE(C, TYPE, SEQ)

static int
codegen_call_exit_with_nones(compiler *c, location loc)
{}

static int
codegen_add_yield_from(compiler *c, location loc, int await)
{}

static int
codegen_pop_except_and_reraise(compiler *c, location loc)
{}

/* Unwind a frame block.  If preserve_tos is true, the TOS before
 * popping the blocks will be restored afterwards, unless another
 * return, break or continue is found. In which case, the TOS will
 * be popped.
 */
static int
codegen_unwind_fblock(compiler *c, location *ploc,
                      fblockinfo *info, int preserve_tos)
{}

/** Unwind block stack. If loop is not NULL, then stop when the first loop is encountered. */
static int
codegen_unwind_fblock_stack(compiler *c, location *ploc,
                            int preserve_tos, fblockinfo **loop)
{}

static int
codegen_enter_scope(compiler *c, identifier name, int scope_type,
                    void *key, int lineno, PyObject *private,
                    _PyCompile_CodeUnitMetadata *umd)
{}

static int
codegen_setup_annotations_scope(compiler *c, location loc,
                                void *key, PyObject *name)
{}

static int
codegen_leave_annotations_scope(compiler *c, location loc,
                                Py_ssize_t annotations_len)
{}

static int
codegen_process_deferred_annotations(compiler *c, location loc)
{}

/* Compile an expression */
int
_PyCodegen_Expression(compiler *c, expr_ty e)
{}

/* Compile a sequence of statements, checking for a docstring
   and for annotations. */

int
_PyCodegen_Body(compiler *c, location loc, asdl_stmt_seq *stmts, bool is_interactive)
{}

int
_PyCodegen_EnterAnonymousScope(compiler* c, mod_ty mod)
{}

static int
codegen_make_closure(compiler *c, location loc,
                     PyCodeObject *co, Py_ssize_t flags)
{}

static int
codegen_decorators(compiler *c, asdl_expr_seq* decos)
{}

static int
codegen_apply_decorators(compiler *c, asdl_expr_seq* decos)
{}

static int
codegen_kwonlydefaults(compiler *c, location loc,
                       asdl_arg_seq *kwonlyargs, asdl_expr_seq *kw_defaults)
{}

static int
codegen_visit_annexpr(compiler *c, expr_ty annotation)
{}

static int
codegen_argannotation(compiler *c, identifier id,
    expr_ty annotation, Py_ssize_t *annotations_len, location loc)
{}

static int
codegen_argannotations(compiler *c, asdl_arg_seq* args,
                       Py_ssize_t *annotations_len, location loc)
{}

static int
codegen_annotations_in_scope(compiler *c, location loc,
                             arguments_ty args, expr_ty returns,
                             Py_ssize_t *annotations_len)
{}

static int
codegen_annotations(compiler *c, location loc,
                    arguments_ty args, expr_ty returns)
{}

static int
codegen_defaults(compiler *c, arguments_ty args,
                        location loc)
{}

static Py_ssize_t
codegen_default_arguments(compiler *c, location loc,
                          arguments_ty args)
{}

static int
codegen_wrap_in_stopiteration_handler(compiler *c)
{}

static int
codegen_type_param_bound_or_default(compiler *c, expr_ty e,
                                    identifier name, void *key,
                                    bool allow_starred)
{}

static int
codegen_type_params(compiler *c, asdl_type_param_seq *type_params)
{}

static int
codegen_function_body(compiler *c, stmt_ty s, int is_async, Py_ssize_t funcflags,
                      int firstlineno)
{}

static int
codegen_function(compiler *c, stmt_ty s, int is_async)
{}

static int
codegen_set_type_params_in_class(compiler *c, location loc)
{}


static int
codegen_class_body(compiler *c, stmt_ty s, int firstlineno)
{}

static int
codegen_class(compiler *c, stmt_ty s)
{}

static int
codegen_typealias_body(compiler *c, stmt_ty s)
{}

static int
codegen_typealias(compiler *c, stmt_ty s)
{}

/* Return false if the expression is a constant value except named singletons.
   Return true otherwise. */
static bool
check_is_arg(expr_ty e)
{}

static PyTypeObject * infer_type(expr_ty e);

/* Check operands of identity checks ("is" and "is not").
   Emit a warning if any operand is a constant except named singletons.
 */
static int
codegen_check_compare(compiler *c, expr_ty e)
{}

static int
codegen_addcompare(compiler *c, location loc, cmpop_ty op)
{}

static int
codegen_jump_if(compiler *c, location loc,
                expr_ty e, jump_target_label next, int cond)
{}

static int
codegen_ifexp(compiler *c, expr_ty e)
{}

static int
codegen_lambda(compiler *c, expr_ty e)
{}

static int
codegen_if(compiler *c, stmt_ty s)
{}

static int
codegen_for(compiler *c, stmt_ty s)
{}


static int
codegen_async_for(compiler *c, stmt_ty s)
{}

static int
codegen_while(compiler *c, stmt_ty s)
{}

static int
codegen_return(compiler *c, stmt_ty s)
{}

static int
codegen_break(compiler *c, location loc)
{}

static int
codegen_continue(compiler *c, location loc)
{}


/* Code generated for "try: <body> finally: <finalbody>" is as follows:

        SETUP_FINALLY           L
        <code for body>
        POP_BLOCK
        <code for finalbody>
        JUMP E
    L:
        <code for finalbody>
    E:

   The special instructions use the block stack.  Each block
   stack entry contains the instruction that created it (here
   SETUP_FINALLY), the level of the value stack at the time the
   block stack entry was created, and a label (here L).

   SETUP_FINALLY:
    Pushes the current value stack level and the label
    onto the block stack.
   POP_BLOCK:
    Pops en entry from the block stack.

   The block stack is unwound when an exception is raised:
   when a SETUP_FINALLY entry is found, the raised and the caught
   exceptions are pushed onto the value stack (and the exception
   condition is cleared), and the interpreter jumps to the label
   gotten from the block stack.
*/

static int
codegen_try_finally(compiler *c, stmt_ty s)
{}

static int
codegen_try_star_finally(compiler *c, stmt_ty s)
{}


/*
   Code generated for "try: S except E1 as V1: S1 except E2 as V2: S2 ...":
   (The contents of the value stack is shown in [], with the top
   at the right; 'tb' is trace-back info, 'val' the exception's
   associated value, and 'exc' the exception.)

   Value stack          Label   Instruction     Argument
   []                           SETUP_FINALLY   L1
   []                           <code for S>
   []                           POP_BLOCK
   []                           JUMP            L0

   [exc]                L1:     <evaluate E1>           )
   [exc, E1]                    CHECK_EXC_MATCH         )
   [exc, bool]                  POP_JUMP_IF_FALSE L2    ) only if E1
   [exc]                        <assign to V1>  (or POP if no V1)
   []                           <code for S1>
                                JUMP            L0

   [exc]                L2:     <evaluate E2>
   .............................etc.......................

   [exc]                Ln+1:   RERAISE     # re-raise exception

   []                   L0:     <next statement>

   Of course, parts are not generated if Vi or Ei is not present.
*/
static int
codegen_try_except(compiler *c, stmt_ty s)
{}

/*
   Code generated for "try: S except* E1 as V1: S1 except* E2 as V2: S2 ...":
   (The contents of the value stack is shown in [], with the top
   at the right; 'tb' is trace-back info, 'val' the exception instance,
   and 'typ' the exception's type.)

   Value stack                   Label         Instruction     Argument
   []                                         SETUP_FINALLY         L1
   []                                         <code for S>
   []                                         POP_BLOCK
   []                                         JUMP                  L0

   [exc]                            L1:       BUILD_LIST   )  list for raised/reraised excs ("result")
   [orig, res]                                COPY 2       )  make a copy of the original EG

   [orig, res, exc]                           <evaluate E1>
   [orig, res, exc, E1]                       CHECK_EG_MATCH
   [orig, res, rest/exc, match?]              COPY 1
   [orig, res, rest/exc, match?, match?]      POP_JUMP_IF_NONE      C1

   [orig, res, rest, match]                   <assign to V1>  (or POP if no V1)

   [orig, res, rest]                          SETUP_FINALLY         R1
   [orig, res, rest]                          <code for S1>
   [orig, res, rest]                          JUMP                  L2

   [orig, res, rest, i, v]          R1:       LIST_APPEND   3 ) exc raised in except* body - add to res
   [orig, res, rest, i]                       POP
   [orig, res, rest]                          JUMP                  LE2

   [orig, res, rest]                L2:       NOP  ) for lineno
   [orig, res, rest]                          JUMP                  LE2

   [orig, res, rest/exc, None]      C1:       POP

   [orig, res, rest]               LE2:       <evaluate E2>
   .............................etc.......................

   [orig, res, rest]                Ln+1:     LIST_APPEND 1  ) add unhandled exc to res (could be None)

   [orig, res]                                CALL_INTRINSIC_2 PREP_RERAISE_STAR
   [exc]                                      COPY 1
   [exc, exc]                                 POP_JUMP_IF_NOT_NONE  RER
   [exc]                                      POP_TOP
   []                                         JUMP                  L0

   [exc]                            RER:      SWAP 2
   [exc, prev_exc_info]                       POP_EXCEPT
   [exc]                                      RERAISE               0

   []                               L0:       <next statement>
*/
static int
codegen_try_star_except(compiler *c, stmt_ty s)
{}

static int
codegen_try(compiler *c, stmt_ty s) {}

static int
codegen_try_star(compiler *c, stmt_ty s)
{}

static int
codegen_import_as(compiler *c, location loc,
                  identifier name, identifier asname)
{}

static int
codegen_import(compiler *c, stmt_ty s)
{}

static int
codegen_from_import(compiler *c, stmt_ty s)
{}

static int
codegen_assert(compiler *c, stmt_ty s)
{}

static int
codegen_stmt_expr(compiler *c, location loc, expr_ty value)
{}

static int
codegen_visit_stmt(compiler *c, stmt_ty s)
{}

static int
unaryop(unaryop_ty op)
{}

static int
addop_binary(compiler *c, location loc, operator_ty binop,
             bool inplace)
{}


static int
codegen_addop_yield(compiler *c, location loc) {}

static int
codegen_load_classdict_freevar(compiler *c, location loc)
{}

static int
codegen_nameop(compiler *c, location loc,
               identifier name, expr_context_ty ctx)
{}

static int
codegen_boolop(compiler *c, expr_ty e)
{}

static int
starunpack_helper_impl(compiler *c, location loc,
                       asdl_expr_seq *elts, PyObject *injected_arg, int pushed,
                       int build, int add, int extend, int tuple)
{}

static int
starunpack_helper(compiler *c, location loc,
                  asdl_expr_seq *elts, int pushed,
                  int build, int add, int extend, int tuple)
{}

static int
unpack_helper(compiler *c, location loc, asdl_expr_seq *elts)
{}

static int
assignment_helper(compiler *c, location loc, asdl_expr_seq *elts)
{}

static int
codegen_list(compiler *c, expr_ty e)
{}

static int
codegen_tuple(compiler *c, expr_ty e)
{}

static int
codegen_set(compiler *c, expr_ty e)
{}

static bool
are_all_items_const(asdl_expr_seq *seq, Py_ssize_t begin, Py_ssize_t end)
{}

static int
codegen_subdict(compiler *c, expr_ty e, Py_ssize_t begin, Py_ssize_t end)
{}

static int
codegen_dict(compiler *c, expr_ty e)
{}

static int
codegen_compare(compiler *c, expr_ty e)
{}

static PyTypeObject *
infer_type(expr_ty e)
{}

static int
check_caller(compiler *c, expr_ty e)
{}

static int
check_subscripter(compiler *c, expr_ty e)
{}

static int
check_index(compiler *c, expr_ty e, expr_ty s)
{}

static int
is_import_originated(compiler *c, expr_ty e)
{}

static int
can_optimize_super_call(compiler *c, expr_ty attr)
{}

static int
load_args_for_super(compiler *c, expr_ty e) {}

// If an attribute access spans multiple lines, update the current start
// location to point to the attribute name.
static location
update_start_location_to_match_attr(compiler *c, location loc,
                                    expr_ty attr)
{}

// Return 1 if the method call was optimized, 0 if not, and -1 on error.
static int
maybe_optimize_method_call(compiler *c, expr_ty e)
{}

static int
codegen_validate_keywords(compiler *c, asdl_keyword_seq *keywords)
{}

static int
codegen_call(compiler *c, expr_ty e)
{}

static int
codegen_joined_str(compiler *c, expr_ty e)
{}

/* Used to implement f-strings. Format a single value. */
static int
codegen_formatted_value(compiler *c, expr_ty e)
{}

static int
codegen_subkwargs(compiler *c, location loc,
                  asdl_keyword_seq *keywords,
                  Py_ssize_t begin, Py_ssize_t end)
{}

/* Used by codegen_call_helper and maybe_optimize_method_call to emit
 * a tuple of keyword names before CALL.
 */
static int
codegen_call_simple_kw_helper(compiler *c, location loc,
                              asdl_keyword_seq *keywords, Py_ssize_t nkwelts)
{}

/* shared code between codegen_call and codegen_class */
static int
codegen_call_helper_impl(compiler *c, location loc,
                         int n, /* Args already pushed */
                         asdl_expr_seq *args,
                         PyObject *injected_arg,
                         asdl_keyword_seq *keywords)
{}

static int
codegen_call_helper(compiler *c, location loc,
                    int n, /* Args already pushed */
                    asdl_expr_seq *args,
                    asdl_keyword_seq *keywords)
{}

/* List and set comprehensions work by being inlined at the location where
  they are defined. The isolation of iteration variables is provided by
  pushing/popping clashing locals on the stack. Generator expressions work
  by creating a nested function to perform the actual iteration.
  This means that the iteration variables don't leak into the current scope.
  See https://peps.python.org/pep-0709/ for additional information.
  The defined function is called immediately following its definition, with the
  result of that call being the result of the expression.
  The LC/SC version returns the populated container, while the GE version is
  flagged in symtable.c as a generator, so it returns the generator object
  when the function is called.

  Possible cleanups:
    - iterate over the generator sequence instead of using recursion
*/


static int
codegen_comprehension_generator(compiler *c, location loc,
                                asdl_comprehension_seq *generators, int gen_index,
                                int depth,
                                expr_ty elt, expr_ty val, int type,
                                int iter_on_stack)
{}

static int
codegen_sync_comprehension_generator(compiler *c, location loc,
                                     asdl_comprehension_seq *generators,
                                     int gen_index, int depth,
                                     expr_ty elt, expr_ty val, int type,
                                     int iter_on_stack)
{}

static int
codegen_async_comprehension_generator(compiler *c, location loc,
                                      asdl_comprehension_seq *generators,
                                      int gen_index, int depth,
                                      expr_ty elt, expr_ty val, int type,
                                      int iter_on_stack)
{}

static int
codegen_push_inlined_comprehension_locals(compiler *c, location loc,
                                          PySTEntryObject *comp,
                                          _PyCompile_InlinedComprehensionState *state)
{}

static int
push_inlined_comprehension_state(compiler *c, location loc,
                                 PySTEntryObject *comp,
                                 _PyCompile_InlinedComprehensionState *state)
{}

static int
restore_inlined_comprehension_locals(compiler *c, location loc,
                                     _PyCompile_InlinedComprehensionState *state)
{}

static int
codegen_pop_inlined_comprehension_locals(compiler *c, location loc,
                                         _PyCompile_InlinedComprehensionState *state)
{}

static int
pop_inlined_comprehension_state(compiler *c, location loc,
                                _PyCompile_InlinedComprehensionState *state)
{}

static inline int
codegen_comprehension_iter(compiler *c, comprehension_ty comp)
{}

static int
codegen_comprehension(compiler *c, expr_ty e, int type,
                      identifier name, asdl_comprehension_seq *generators, expr_ty elt,
                      expr_ty val)
{}

static int
codegen_genexp(compiler *c, expr_ty e)
{}

static int
codegen_listcomp(compiler *c, expr_ty e)
{}

static int
codegen_setcomp(compiler *c, expr_ty e)
{}


static int
codegen_dictcomp(compiler *c, expr_ty e)
{}


static int
codegen_visit_keyword(compiler *c, keyword_ty k)
{}


static int
codegen_with_except_finish(compiler *c, jump_target_label cleanup) {}

/*
   Implements the async with statement.

   The semantics outlined in that PEP are as follows:

   async with EXPR as VAR:
       BLOCK

   It is implemented roughly as:

   context = EXPR
   exit = context.__aexit__  # not calling it
   value = await context.__aenter__()
   try:
       VAR = value  # if VAR present in the syntax
       BLOCK
   finally:
       if an exception was raised:
           exc = copy of (exception, instance, traceback)
       else:
           exc = (None, None, None)
       if not (await exit(*exc)):
           raise
 */
static int
codegen_async_with(compiler *c, stmt_ty s, int pos)
{}


/*
   Implements the with statement from PEP 343.
   with EXPR as VAR:
       BLOCK
   is implemented as:
        <code for EXPR>
        SETUP_WITH  E
        <code to store to VAR> or POP_TOP
        <code for BLOCK>
        LOAD_CONST (None, None, None)
        CALL_FUNCTION_EX 0
        JUMP  EXIT
    E:  WITH_EXCEPT_START (calls EXPR.__exit__)
        POP_JUMP_IF_TRUE T:
        RERAISE
    T:  POP_TOP (remove exception from stack)
        POP_EXCEPT
        POP_TOP
    EXIT:
 */

static int
codegen_with(compiler *c, stmt_ty s, int pos)
{}

static int
codegen_visit_expr(compiler *c, expr_ty e)
{}

static bool
is_constant_slice(expr_ty s)
{}

static bool
should_apply_two_element_slice_optimization(expr_ty s)
{}

static int
codegen_augassign(compiler *c, stmt_ty s)
{}

static int
codegen_check_ann_expr(compiler *c, expr_ty e)
{}

static int
codegen_check_annotation(compiler *c, stmt_ty s)
{}

static int
codegen_check_ann_subscr(compiler *c, expr_ty e)
{}

static int
codegen_annassign(compiler *c, stmt_ty s)
{}

static int
codegen_subscript(compiler *c, expr_ty e)
{}

static int
codegen_slice_two_parts(compiler *c, expr_ty s)
{}

static int
codegen_slice(compiler *c, expr_ty s)
{}


// PEP 634: Structural Pattern Matching

// To keep things simple, all codegen_pattern_* routines follow the convention
// of consuming TOS (the subject for the given pattern) and calling
// jump_to_fail_pop on failure (no match).

// When calling into these routines, it's important that pc->on_top be kept
// updated to reflect the current number of items that we are using on the top
// of the stack: they will be popped on failure, and any name captures will be
// stored *underneath* them on success. This lets us defer all names stores
// until the *entire* pattern matches.

#define WILDCARD_CHECK

#define WILDCARD_STAR_CHECK

// Limit permitted subexpressions, even if the parser & AST validator let them through
#define MATCH_VALUE_EXPR(N)

// Allocate or resize pc->fail_pop to allow for n items to be popped on failure.
static int
ensure_fail_pop(compiler *c, pattern_context *pc, Py_ssize_t n)
{}

// Use op to jump to the correct fail_pop block.
static int
jump_to_fail_pop(compiler *c, location loc,
                 pattern_context *pc, int op)
{}

// Build all of the fail_pop blocks and reset fail_pop.
static int
emit_and_reset_fail_pop(compiler *c, location loc,
                        pattern_context *pc)
{}

static int
codegen_error_duplicate_store(compiler *c, location loc, identifier n)
{}

// Duplicate the effect of 3.10's ROT_* instructions using SWAPs.
static int
codegen_pattern_helper_rotate(compiler *c, location loc, Py_ssize_t count)
{}

static int
codegen_pattern_helper_store_name(compiler *c, location loc,
                                  identifier n, pattern_context *pc)
{}


static int
codegen_pattern_unpack_helper(compiler *c, location loc,
                              asdl_pattern_seq *elts)
{}

static int
pattern_helper_sequence_unpack(compiler *c, location loc,
                               asdl_pattern_seq *patterns, Py_ssize_t star,
                               pattern_context *pc)
{}

// Like pattern_helper_sequence_unpack, but uses BINARY_SUBSCR instead of
// UNPACK_SEQUENCE / UNPACK_EX. This is more efficient for patterns with a
// starred wildcard like [first, *_] / [first, *_, last] / [*_, last] / etc.
static int
pattern_helper_sequence_subscr(compiler *c, location loc,
                               asdl_pattern_seq *patterns, Py_ssize_t star,
                               pattern_context *pc)
{}

// Like codegen_pattern, but turn off checks for irrefutability.
static int
codegen_pattern_subpattern(compiler *c,
                            pattern_ty p, pattern_context *pc)
{}

static int
codegen_pattern_as(compiler *c, pattern_ty p, pattern_context *pc)
{}

static int
codegen_pattern_star(compiler *c, pattern_ty p, pattern_context *pc)
{}

static int
validate_kwd_attrs(compiler *c, asdl_identifier_seq *attrs, asdl_pattern_seq* patterns)
{}

static int
codegen_pattern_class(compiler *c, pattern_ty p, pattern_context *pc)
{}

static int
codegen_pattern_mapping_key(compiler *c, PyObject *seen, pattern_ty p, Py_ssize_t i)
{}

static int
codegen_pattern_mapping(compiler *c, pattern_ty p,
                        pattern_context *pc)
{}

static int
codegen_pattern_or(compiler *c, pattern_ty p, pattern_context *pc)
{}


static int
codegen_pattern_sequence(compiler *c, pattern_ty p,
                         pattern_context *pc)
{}

static int
codegen_pattern_value(compiler *c, pattern_ty p, pattern_context *pc)
{}

static int
codegen_pattern_singleton(compiler *c, pattern_ty p, pattern_context *pc)
{}

static int
codegen_pattern(compiler *c, pattern_ty p, pattern_context *pc)
{}

static int
codegen_match_inner(compiler *c, stmt_ty s, pattern_context *pc)
{}

static int
codegen_match(compiler *c, stmt_ty s)
{}

#undef WILDCARD_CHECK
#undef WILDCARD_STAR_CHECK


int
_PyCodegen_AddReturnAtEnd(compiler *c, int addNone)
{}