summaryrefslogtreecommitdiffstats
path: root/Python/ast_opt.c
diff options
context:
space:
mode:
authorBrandt Bucher <brandtbucher@gmail.com>2021-02-26 22:51:55 (GMT)
committerGitHub <noreply@github.com>2021-02-26 22:51:55 (GMT)
commit145bf269df3530176f6ebeab1324890ef7070bf8 (patch)
tree4c4928d6250785372171a52be0b7269aa444511b /Python/ast_opt.c
parentcc02b4f2e810ab524d845daa18bc94df5b092dd8 (diff)
downloadcpython-145bf269df3530176f6ebeab1324890ef7070bf8.zip
cpython-145bf269df3530176f6ebeab1324890ef7070bf8.tar.gz
cpython-145bf269df3530176f6ebeab1324890ef7070bf8.tar.bz2
bpo-42128: Structural Pattern Matching (PEP 634) (GH-22917)
Co-authored-by: Guido van Rossum <guido@python.org> Co-authored-by: Talin <viridia@gmail.com> Co-authored-by: Pablo Galindo <pablogsal@gmail.com>
Diffstat (limited to 'Python/ast_opt.c')
-rw-r--r--Python/ast_opt.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/Python/ast_opt.c b/Python/ast_opt.c
index 8c958ca..6ad00dc 100644
--- a/Python/ast_opt.c
+++ b/Python/ast_opt.c
@@ -408,6 +408,9 @@ static int astfold_comprehension(comprehension_ty node_, PyArena *ctx_, _PyASTOp
static int astfold_keyword(keyword_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
static int astfold_withitem(withitem_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
static int astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
+static int astfold_match_case(match_case_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
+static int astfold_pattern(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state);
+
#define CALL(FUNC, TYPE, ARG) \
if (!FUNC((ARG), ctx_, state)) \
return 0;
@@ -590,6 +593,10 @@ astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
case Constant_kind:
// Already a constant, nothing further to do
break;
+ case MatchAs_kind:
+ case MatchOr_kind:
+ // These can't occur outside of patterns.
+ Py_UNREACHABLE();
// No default case, so the compiler will emit a warning if new expression
// kinds are added without being handled here
}
@@ -709,6 +716,10 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
case Expr_kind:
CALL(astfold_expr, expr_ty, node_->v.Expr.value);
break;
+ case Match_kind:
+ CALL(astfold_expr, expr_ty, node_->v.Match.subject);
+ CALL_SEQ(astfold_match_case, match_case, node_->v.Match.cases);
+ break;
// The following statements don't contain any subexpressions to be folded
case Import_kind:
case ImportFrom_kind:
@@ -746,6 +757,125 @@ astfold_withitem(withitem_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
return 1;
}
+static int
+astfold_pattern_negative(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
+{
+ assert(node_->kind == UnaryOp_kind);
+ assert(node_->v.UnaryOp.op == USub);
+ assert(node_->v.UnaryOp.operand->kind == Constant_kind);
+ PyObject *value = node_->v.UnaryOp.operand->v.Constant.value;
+ assert(PyComplex_CheckExact(value) ||
+ PyFloat_CheckExact(value) ||
+ PyLong_CheckExact(value));
+ PyObject *negated = PyNumber_Negative(value);
+ if (negated == NULL) {
+ return 0;
+ }
+ assert(PyComplex_CheckExact(negated) ||
+ PyFloat_CheckExact(negated) ||
+ PyLong_CheckExact(negated));
+ return make_const(node_, negated, ctx_);
+}
+
+static int
+astfold_pattern_complex(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
+{
+ expr_ty left = node_->v.BinOp.left;
+ expr_ty right = node_->v.BinOp.right;
+ if (left->kind == UnaryOp_kind) {
+ CALL(astfold_pattern_negative, expr_ty, left);
+ }
+ assert(left->kind = Constant_kind);
+ assert(right->kind = Constant_kind);
+ // LHS must be real, RHS must be imaginary:
+ if (!(PyFloat_CheckExact(left->v.Constant.value) ||
+ PyLong_CheckExact(left->v.Constant.value)) ||
+ !PyComplex_CheckExact(right->v.Constant.value))
+ {
+ // Not actually valid, but it's the compiler's job to complain:
+ return 1;
+ }
+ PyObject *new;
+ if (node_->v.BinOp.op == Add) {
+ new = PyNumber_Add(left->v.Constant.value, right->v.Constant.value);
+ }
+ else {
+ assert(node_->v.BinOp.op == Sub);
+ new = PyNumber_Subtract(left->v.Constant.value, right->v.Constant.value);
+ }
+ if (new == NULL) {
+ return 0;
+ }
+ assert(PyComplex_CheckExact(new));
+ return make_const(node_, new, ctx_);
+}
+
+static int
+astfold_pattern_keyword(keyword_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
+{
+ CALL(astfold_pattern, expr_ty, node_->value);
+ return 1;
+}
+
+static int
+astfold_pattern(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
+{
+ // Don't blindly optimize the pattern as an expr; it plays by its own rules!
+ // Currently, this is only used to form complex/negative numeric constants.
+ switch (node_->kind) {
+ case Attribute_kind:
+ break;
+ case BinOp_kind:
+ CALL(astfold_pattern_complex, expr_ty, node_);
+ break;
+ case Call_kind:
+ CALL_SEQ(astfold_pattern, expr, node_->v.Call.args);
+ CALL_SEQ(astfold_pattern_keyword, keyword, node_->v.Call.keywords);
+ break;
+ case Constant_kind:
+ break;
+ case Dict_kind:
+ CALL_SEQ(astfold_pattern, expr, node_->v.Dict.keys);
+ CALL_SEQ(astfold_pattern, expr, node_->v.Dict.values);
+ break;
+ // Not actually valid, but it's the compiler's job to complain:
+ case JoinedStr_kind:
+ break;
+ case List_kind:
+ CALL_SEQ(astfold_pattern, expr, node_->v.List.elts);
+ break;
+ case MatchAs_kind:
+ CALL(astfold_pattern, expr_ty, node_->v.MatchAs.pattern);
+ break;
+ case MatchOr_kind:
+ CALL_SEQ(astfold_pattern, expr, node_->v.MatchOr.patterns);
+ break;
+ case Name_kind:
+ break;
+ case Starred_kind:
+ CALL(astfold_pattern, expr_ty, node_->v.Starred.value);
+ break;
+ case Tuple_kind:
+ CALL_SEQ(astfold_pattern, expr, node_->v.Tuple.elts);
+ break;
+ case UnaryOp_kind:
+ CALL(astfold_pattern_negative, expr_ty, node_);
+ break;
+ default:
+ Py_UNREACHABLE();
+ }
+ return 1;
+}
+
+static int
+astfold_match_case(match_case_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
+{
+ CALL(astfold_pattern, expr_ty, node_->pattern);
+ CALL_OPT(astfold_expr, expr_ty, node_->guard);
+ CALL_SEQ(astfold_stmt, stmt, node_->body);
+ return 1;
+}
+
#undef CALL
#undef CALL_OPT
#undef CALL_SEQ