Skip to content

Commit ca7743c

Browse files
committed
ctypes
1 parent a4c93df commit ca7743c

File tree

28 files changed

+8633
-3345
lines changed

28 files changed

+8633
-3345
lines changed

.cspell.dict/python-more.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ nbytes
148148
ncallbacks
149149
ndigits
150150
ndim
151+
needsfree
151152
nldecoder
152153
nlocals
153154
NOARGS
@@ -168,6 +169,7 @@ pycache
168169
pycodecs
169170
pycs
170171
pyexpat
172+
PYTHONAPI
171173
PYTHONBREAKPOINT
172174
PYTHONDEBUG
173175
PYTHONDONTWRITEBYTECODE

.cspell.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@
7575
"makeunicodedata",
7676
"miri",
7777
"notrace",
78+
"oparg",
7879
"openat",
7980
"pyarg",
80-
"pyarg",
8181
"pyargs",
8282
"pyast",
8383
"PyAttr",
@@ -107,6 +107,7 @@
107107
"pystruct",
108108
"pystructseq",
109109
"pytrace",
110+
"pytype",
110111
"reducelib",
111112
"richcompare",
112113
"RustPython",
@@ -116,7 +117,6 @@
116117
"sysmodule",
117118
"tracebacks",
118119
"typealiases",
119-
"unconstructible",
120120
"unhashable",
121121
"uninit",
122122
"unraisable",
@@ -131,6 +131,7 @@
131131
"getrusage",
132132
"nanosleep",
133133
"sigaction",
134+
"sighandler",
134135
"WRLCK",
135136
// win32
136137
"birthtime",

crates/stdlib/src/pystruct.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub(crate) mod _struct {
2828
// CPython turns str to bytes but we do reversed way here
2929
// The only performance difference is this transition cost
3030
let fmt = match_class!(match obj {
31-
s @ PyStr => s.is_ascii().then_some(s),
31+
s @ PyStr => s.isascii().then_some(s),
3232
b @ PyBytes => ascii::AsciiStr::from_ascii(&b)
3333
.ok()
3434
.map(|s| vm.ctx.new_str(s)),

crates/vm/src/buffer.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,56 @@ impl FormatCode {
261261
return Err("embedded null character".to_owned());
262262
}
263263

264+
// PEP3118: Handle extended format specifiers
265+
// T{...} - struct, X{} - function pointer, (...) - array shape, :name: - field name
266+
if c == b'T' || c == b'X' {
267+
// Skip struct/function pointer: consume until matching '}'
268+
if chars.peek() == Some(&b'{') {
269+
chars.next(); // consume '{'
270+
let mut depth = 1;
271+
while depth > 0 {
272+
match chars.next() {
273+
Some(b'{') => depth += 1,
274+
Some(b'}') => depth -= 1,
275+
None => return Err("unmatched '{' in format".to_owned()),
276+
_ => {}
277+
}
278+
}
279+
continue;
280+
}
281+
}
282+
283+
if c == b'(' {
284+
// Skip array shape: consume until matching ')'
285+
let mut depth = 1;
286+
while depth > 0 {
287+
match chars.next() {
288+
Some(b'(') => depth += 1,
289+
Some(b')') => depth -= 1,
290+
None => return Err("unmatched '(' in format".to_owned()),
291+
_ => {}
292+
}
293+
}
294+
continue;
295+
}
296+
297+
if c == b':' {
298+
// Skip field name: consume until next ':'
299+
loop {
300+
match chars.next() {
301+
Some(b':') => break,
302+
None => return Err("unmatched ':' in format".to_owned()),
303+
_ => {}
304+
}
305+
}
306+
continue;
307+
}
308+
309+
if c == b'{' || c == b'}' {
310+
// Skip standalone braces (pointer targets, etc.)
311+
continue;
312+
}
313+
264314
let code = FormatType::try_from(c)
265315
.ok()
266316
.filter(|c| match c {

crates/vm/src/builtins/builtin_func.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ impl PyNativeFunction {
114114
zelf.0.value.doc
115115
}
116116

117-
#[pygetset(name = "__self__")]
117+
#[pygetset]
118118
fn __self__(_zelf: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
119119
vm.ctx.none()
120120
}
@@ -181,7 +181,7 @@ impl PyNativeMethod {
181181
Ok((getattr, (target, name)))
182182
}
183183

184-
#[pygetset(name = "__self__")]
184+
#[pygetset]
185185
fn __self__(zelf: PyRef<Self>, _vm: &VirtualMachine) -> Option<PyObjectRef> {
186186
zelf.func.zelf.clone()
187187
}

crates/vm/src/builtins/function.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -629,12 +629,11 @@ impl GetDescriptor for PyFunction {
629629
vm: &VirtualMachine,
630630
) -> PyResult {
631631
let (_zelf, obj) = Self::_unwrap(&zelf, obj, vm)?;
632-
let obj = if vm.is_none(&obj) && !Self::_cls_is(&cls, obj.class()) {
632+
Ok(if vm.is_none(&obj) && !Self::_cls_is(&cls, obj.class()) {
633633
zelf
634634
} else {
635635
PyBoundMethod::new(obj, zelf).into_ref(&vm.ctx).into()
636-
};
637-
Ok(obj)
636+
})
638637
}
639638
}
640639

crates/vm/src/builtins/object.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,8 +450,8 @@ impl PyBaseObject {
450450
Ok(())
451451
}
452452

453-
#[pygetset(name = "__class__")]
454-
fn get_class(obj: PyObjectRef) -> PyTypeRef {
453+
#[pygetset]
454+
fn __class__(obj: PyObjectRef) -> PyTypeRef {
455455
obj.class().to_owned()
456456
}
457457

crates/vm/src/builtins/str.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -625,9 +625,9 @@ impl PyStr {
625625
self.data.char_len()
626626
}
627627

628-
#[pymethod(name = "isascii")]
628+
#[pymethod]
629629
#[inline(always)]
630-
pub const fn is_ascii(&self) -> bool {
630+
pub const fn isascii(&self) -> bool {
631631
matches!(self.kind(), StrKind::Ascii)
632632
}
633633

@@ -960,7 +960,7 @@ impl PyStr {
960960
format_map(&format_string, &mapping, vm)
961961
}
962962

963-
#[pymethod(name = "__format__")]
963+
#[pymethod]
964964
fn __format__(
965965
zelf: PyRef<PyStr>,
966966
spec: PyStrRef,

crates/vm/src/builtins/type.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,8 +1445,8 @@ impl GetAttr for PyType {
14451445

14461446
#[pyclass]
14471447
impl Py<PyType> {
1448-
#[pygetset(name = "__mro__")]
1449-
fn get_mro(&self) -> PyTuple {
1448+
#[pygetset]
1449+
fn __mro__(&self) -> PyTuple {
14501450
let elements: Vec<PyObjectRef> = self.mro_map_collect(|x| x.as_object().to_owned());
14511451
PyTuple::new_unchecked(elements.into_boxed_slice())
14521452
}

crates/vm/src/exceptions.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -624,8 +624,8 @@ impl PyBaseException {
624624
*self.context.write() = context;
625625
}
626626

627-
#[pygetset(name = "__suppress_context__")]
628-
pub(super) fn get_suppress_context(&self) -> bool {
627+
#[pygetset]
628+
pub(super) fn __suppress_context__(&self) -> bool {
629629
self.suppress_context.load()
630630
}
631631

@@ -1112,7 +1112,7 @@ impl serde::Serialize for SerializeException<'_, '_> {
11121112
.__context__()
11131113
.map(|exc| SerializeExceptionOwned { vm: self.vm, exc }),
11141114
)?;
1115-
struc.serialize_field("suppress_context", &self.exc.get_suppress_context())?;
1115+
struc.serialize_field("suppress_context", &self.exc.__suppress_context__())?;
11161116

11171117
let args = {
11181118
struct Args<'vm>(&'vm VirtualMachine, PyTupleRef);
@@ -1857,8 +1857,8 @@ pub(super) mod types {
18571857
self.errno.swap_to_temporary_refs(value, vm);
18581858
}
18591859

1860-
#[pygetset(name = "strerror")]
1861-
fn get_strerror(&self) -> Option<PyObjectRef> {
1860+
#[pygetset]
1861+
fn strerror(&self) -> Option<PyObjectRef> {
18621862
self.strerror.to_owned()
18631863
}
18641864

0 commit comments

Comments
 (0)