mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
MATCH_SELF
This commit is contained in:
1 parent
50c557419e
commit
8ae2dc75f6
13 files changed
+32
-38
No files matched your search
@@ -36,7 +36,7 @@ use rustpython_compiler_core::{
|
||||
Mode, OneIndexed, SourceFile, SourceLocation,
|
||||
bytecode::{
|
||||
self, Arg as OpArgMarker, BinaryOperator, CodeObject, ComparisonOperator, ConstantData,
|
||||
Instruction, OpArg, OpArgType, TestOperator, UnpackExArgs,
|
||||
Instruction, OpArg, OpArgType, UnpackExArgs,
|
||||
},
|
||||
};
|
||||
use rustpython_wtf8::Wtf8Buf;
|
||||
@@ -3484,7 +3484,7 @@ impl Compiler {
|
||||
|
||||
// Process each sub-pattern.
|
||||
for subpattern in patterns.iter().chain(kwd_patterns.iter()) {
|
||||
// Decrement the on_top counter BEFORE processing each sub-pattern
|
||||
// Decrement the on_top counter before processing each sub-pattern
|
||||
pc.on_top -= 1;
|
||||
|
||||
// Check if this is a true wildcard (underscore pattern without name binding)
|
||||
@@ -3557,6 +3557,7 @@ impl Compiler {
|
||||
// Check if the mapping has at least 'size' keys
|
||||
emit!(self, Instruction::GetLen);
|
||||
self.emit_load_const(ConstantData::Integer { value: size.into() });
|
||||
// Stack: [subject, len, size]
|
||||
emit!(
|
||||
self,
|
||||
Instruction::CompareOperation {
|
||||
@@ -3564,6 +3565,7 @@ impl Compiler {
|
||||
}
|
||||
);
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
|
||||
// Stack: [subject]
|
||||
}
|
||||
|
||||
// Check for overflow (INT_MAX < size - 1)
|
||||
@@ -3606,9 +3608,8 @@ impl Compiler {
|
||||
|
||||
self.compile_expression(key)?;
|
||||
}
|
||||
// Stack: [subject, key1, key2, ..., keyn]
|
||||
}
|
||||
// Stack: [subject] if size==0, or [subject, key1, ..., keyn] if size>0
|
||||
// Stack: [subject, key1, key2, ..., key_n]
|
||||
|
||||
// Build tuple of keys (empty tuple if size==0)
|
||||
emit!(self, Instruction::BuildTuple { size });
|
||||
@@ -3628,7 +3629,7 @@ impl Compiler {
|
||||
emit!(
|
||||
self,
|
||||
Instruction::TestOperation {
|
||||
op: TestOperator::IsNot
|
||||
op: bytecode::TestOperator::IsNot
|
||||
}
|
||||
);
|
||||
// Stack: [subject, keys_tuple, values_tuple, bool]
|
||||
@@ -3924,8 +3925,7 @@ impl Compiler {
|
||||
Singleton::False => ConstantData::Boolean { value: false },
|
||||
Singleton::True => ConstantData::Boolean { value: true },
|
||||
});
|
||||
// Compare using the "Is" operator (identity check, not equality).
|
||||
// This is important: False should not match 0, even though False == 0
|
||||
// Compare using the "Is" operator.
|
||||
emit!(
|
||||
self,
|
||||
Instruction::TestOperation {
|
||||
|
||||
@@ -109,7 +109,7 @@ impl Constructor for PyBool {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(with(Constructor, AsNumber, Representable))]
|
||||
#[pyclass(with(Constructor, AsNumber, Representable), flags(_MATCH_SELF))]
|
||||
impl PyBool {
|
||||
#[pymethod]
|
||||
fn __format__(obj: PyObjectRef, spec: PyStrRef, vm: &VirtualMachine) -> PyResult<String> {
|
||||
|
||||
@@ -170,7 +170,7 @@ impl PyByteArray {
|
||||
}
|
||||
|
||||
#[pyclass(
|
||||
flags(BASETYPE),
|
||||
flags(BASETYPE, _MATCH_SELF),
|
||||
with(
|
||||
Py,
|
||||
PyRef,
|
||||
|
||||
@@ -132,7 +132,7 @@ impl PyRef<PyBytes> {
|
||||
}
|
||||
|
||||
#[pyclass(
|
||||
flags(BASETYPE),
|
||||
flags(BASETYPE, _MATCH_SELF),
|
||||
with(
|
||||
Py,
|
||||
PyRef,
|
||||
|
||||
@@ -176,7 +176,7 @@ impl PyDict {
|
||||
AsMapping,
|
||||
Representable
|
||||
),
|
||||
flags(BASETYPE, MAPPING)
|
||||
flags(BASETYPE, MAPPING, _MATCH_SELF)
|
||||
)]
|
||||
impl PyDict {
|
||||
#[pyclassmethod]
|
||||
|
||||
@@ -201,7 +201,7 @@ fn float_from_string(val: PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> {
|
||||
}
|
||||
|
||||
#[pyclass(
|
||||
flags(BASETYPE),
|
||||
flags(BASETYPE, _MATCH_SELF),
|
||||
with(Comparable, Hashable, Constructor, AsNumber, Representable)
|
||||
)]
|
||||
impl PyFloat {
|
||||
|
||||
@@ -317,7 +317,7 @@ impl PyInt {
|
||||
}
|
||||
|
||||
#[pyclass(
|
||||
flags(BASETYPE),
|
||||
flags(BASETYPE, _MATCH_SELF),
|
||||
with(PyRef, Comparable, Hashable, Constructor, AsNumber, Representable)
|
||||
)]
|
||||
impl PyInt {
|
||||
|
||||
@@ -109,7 +109,7 @@ pub type PyListRef = PyRef<PyList>;
|
||||
AsSequence,
|
||||
Representable
|
||||
),
|
||||
flags(BASETYPE, SEQUENCE)
|
||||
flags(BASETYPE, SEQUENCE, _MATCH_SELF)
|
||||
)]
|
||||
impl PyList {
|
||||
#[pymethod]
|
||||
|
||||
@@ -529,7 +529,7 @@ fn reduce_set(
|
||||
AsNumber,
|
||||
Representable
|
||||
),
|
||||
flags(BASETYPE)
|
||||
flags(BASETYPE, _MATCH_SELF)
|
||||
)]
|
||||
impl PySet {
|
||||
#[pymethod]
|
||||
@@ -946,7 +946,7 @@ impl Constructor for PyFrozenSet {
|
||||
}
|
||||
|
||||
#[pyclass(
|
||||
flags(BASETYPE),
|
||||
flags(BASETYPE, _MATCH_SELF),
|
||||
with(
|
||||
Constructor,
|
||||
AsSequence,
|
||||
|
||||
@@ -521,7 +521,7 @@ impl Py<PyStr> {
|
||||
}
|
||||
|
||||
#[pyclass(
|
||||
flags(BASETYPE),
|
||||
flags(BASETYPE, _MATCH_SELF),
|
||||
with(
|
||||
PyRef,
|
||||
AsMapping,
|
||||
|
||||
@@ -244,7 +244,7 @@ impl<T> PyTuple<PyRef<T>> {
|
||||
}
|
||||
|
||||
#[pyclass(
|
||||
flags(BASETYPE, SEQUENCE),
|
||||
flags(BASETYPE, SEQUENCE, _MATCH_SELF),
|
||||
with(
|
||||
AsMapping,
|
||||
AsSequence,
|
||||
|
||||
+10
-20
@@ -702,19 +702,17 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
bytecode::Instruction::Swap { index } => {
|
||||
let len = self.state.stack.len();
|
||||
if len == 0 {
|
||||
return Err(vm.new_runtime_error("stack underflow in SWAP".to_string()));
|
||||
}
|
||||
debug_assert!(len > 0, "stack underflow in SWAP");
|
||||
let i = len - 1; // TOS index
|
||||
let index_val = index.get(arg) as usize;
|
||||
// CPython: SWAP(n) swaps TOS with PEEK(n) where PEEK(n) = stack_pointer[-n]
|
||||
// This means swap TOS with the element at index (len - n)
|
||||
if index_val > len {
|
||||
return Err(vm.new_runtime_error(format!(
|
||||
"SWAP index {} exceeds stack size {}",
|
||||
index_val, len
|
||||
)));
|
||||
}
|
||||
debug_assert!(
|
||||
index_val <= len,
|
||||
"SWAP index {} exceeds stack size {}",
|
||||
index_val,
|
||||
len
|
||||
);
|
||||
let j = len - index_val;
|
||||
self.state.stack.swap(i, j);
|
||||
Ok(None)
|
||||
@@ -1433,17 +1431,9 @@ impl ExecutingFrame<'_> {
|
||||
// No __match_args__, check if this is a type with MATCH_SELF behavior
|
||||
// For built-in types like bool, int, str, list, tuple, dict, etc.
|
||||
// they match the subject itself as the single positional argument
|
||||
let is_match_self_type = cls.is(vm.ctx.types.bool_type)
|
||||
|| cls.is(vm.ctx.types.int_type)
|
||||
|| cls.is(vm.ctx.types.float_type)
|
||||
|| cls.is(vm.ctx.types.str_type)
|
||||
|| cls.is(vm.ctx.types.bytes_type)
|
||||
|| cls.is(vm.ctx.types.bytearray_type)
|
||||
|| cls.is(vm.ctx.types.list_type)
|
||||
|| cls.is(vm.ctx.types.tuple_type)
|
||||
|| cls.is(vm.ctx.types.dict_type)
|
||||
|| cls.is(vm.ctx.types.set_type)
|
||||
|| cls.is(vm.ctx.types.frozenset_type);
|
||||
let is_match_self_type = cls
|
||||
.downcast::<PyType>()
|
||||
.is_ok_and(|t| t.slots.flags.contains(PyTypeFlags::_MATCH_SELF));
|
||||
|
||||
if is_match_self_type {
|
||||
if nargs_val == 1 {
|
||||
|
||||
@@ -129,6 +129,10 @@ bitflags! {
|
||||
const HEAPTYPE = 1 << 9;
|
||||
const BASETYPE = 1 << 10;
|
||||
const METHOD_DESCRIPTOR = 1 << 17;
|
||||
// For built-in types that match the subject itself in pattern matching
|
||||
// (bool, int, float, str, bytes, bytearray, list, tuple, dict, set, frozenset)
|
||||
// This is not a stable API
|
||||
const _MATCH_SELF = 1 << 22;
|
||||
const HAS_DICT = 1 << 40;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
|
||||
Reference in new issue
Block a user