Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

394 changes: 165 additions & 229 deletions crates/codegen/src/compile.rs

Large diffs are not rendered by default.

345 changes: 112 additions & 233 deletions crates/codegen/src/ir.rs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions crates/codegen/src/string_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use rustpython_wtf8::{CodePoint, Wtf8, Wtf8Buf};
// use ruff_python_parser::{LexicalError, LexicalErrorType};
type LexicalError = Infallible;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum EscapedChar {
Literal(CodePoint),
Escape(char),
Expand Down
1 change: 1 addition & 0 deletions crates/compiler-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ bitflagset = { workspace = true }
itertools = { workspace = true }
malachite-bigint = { workspace = true }
num-complex = { workspace = true }
num-traits = { workspace = true }

lz4_flex = { workspace = true }

Expand Down
26 changes: 26 additions & 0 deletions crates/compiler-core/src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use core::{
use itertools::Itertools;
use malachite_bigint::BigInt;
use num_complex::Complex64;
use num_traits::Zero;
use rustpython_wtf8::{Wtf8, Wtf8Buf};

pub use crate::bytecode::{
Expand Down Expand Up @@ -909,6 +910,31 @@ pub enum ConstantData {
Ellipsis,
}

impl ConstantData {
/// Whether or not python would return True/False for the given constant data.
///
/// ```py
/// bool(0) # False
/// bool(1) # True
/// bool([]) # False
/// bool(...) # True
/// ```
#[must_use]
pub fn truthiness(&self) -> bool {
match self {
Self::Tuple { elements } | Self::Frozenset { elements } => !elements.is_empty(),
Self::Integer { value } => !value.is_zero(),
Self::Float { value } => *value != 0.0,
Self::Complex { value } => value.re != 0.0 || value.im != 0.0,
Self::Boolean { value } => *value,
Self::Str { value } => !value.is_empty(),
Self::Bytes { value } => !value.is_empty(),
Self::Code { .. } | Self::Slice { .. } | Self::Ellipsis => true,
Self::None => false,
}
}
}

impl PartialEq for ConstantData {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
Expand Down
23 changes: 12 additions & 11 deletions crates/vm/src/function/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,21 @@ use crate::{
pub struct ArgBytesLike(PyBuffer);

impl PyObject {
pub fn try_bytes_like<R>(
&self,
vm: &VirtualMachine,
f: impl FnOnce(&[u8]) -> R,
) -> PyResult<R> {
pub fn try_bytes_like<F, R>(&self, vm: &VirtualMachine, f: F) -> PyResult<R>
where
F: FnOnce(&[u8]) -> R,
{
let buffer = PyBuffer::try_from_borrowed_object(vm, self)?;
buffer
.as_contiguous()
.map(|x| f(&x))
.ok_or_else(|| vm.new_buffer_error("non-contiguous buffer is not a bytes-like object"))
}

pub fn try_rw_bytes_like<R>(
&self,
vm: &VirtualMachine,
f: impl FnOnce(&mut [u8]) -> R,
) -> PyResult<R> {
pub fn try_rw_bytes_like<F, R>(&self, vm: &VirtualMachine, f: F) -> PyResult<R>
where
F: FnOnce(&mut [u8]) -> R,
{
let buffer = PyBuffer::try_from_borrowed_object(vm, self)?;
buffer
.as_contiguous_mut()
Expand Down Expand Up @@ -207,7 +205,10 @@ impl ArgAsciiBuffer {
}

#[inline]
pub fn with_ref<R>(&self, f: impl FnOnce(&[u8]) -> R) -> R {
pub fn with_ref<F, R>(&self, f: F) -> R
where
F: FnOnce(&[u8]) -> R,
{
match self {
Self::String(s) => f(s.as_bytes()),
Self::Buffer(buffer) => buffer.with_ref(f),
Expand Down
7 changes: 5 additions & 2 deletions crates/vm/src/function/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ pub trait PyNativeFn:
Fn(&VirtualMachine, FuncArgs) -> PyResult + PyThreadingConstraint + 'static
{
}
impl<F: Fn(&VirtualMachine, FuncArgs) -> PyResult + PyThreadingConstraint + 'static> PyNativeFn
for F

impl<F> PyNativeFn for F where
F: Fn(&VirtualMachine, FuncArgs) -> PyResult + PyThreadingConstraint + 'static
{
}

Expand Down Expand Up @@ -103,8 +104,10 @@ use sealed::PyNativeFnInternal;

#[doc(hidden)]
pub struct OwnedParam<T>(PhantomData<T>);

#[doc(hidden)]
pub struct BorrowedParam<T>(PhantomData<T>);

#[doc(hidden)]
pub struct RefParam<T>(PhantomData<T>);

Expand Down
24 changes: 20 additions & 4 deletions crates/vm/src/function/either.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ pub enum Either<A, B> {
B(B),
}

impl<A: Borrow<PyObject>, B: Borrow<PyObject>> Borrow<PyObject> for Either<A, B> {
impl<A, B> Borrow<PyObject> for Either<A, B>
where
A: Borrow<PyObject>,
B: Borrow<PyObject>,
{
#[inline(always)]
fn borrow(&self) -> &PyObject {
match self {
Expand All @@ -18,7 +22,11 @@ impl<A: Borrow<PyObject>, B: Borrow<PyObject>> Borrow<PyObject> for Either<A, B>
}
}

impl<A: AsRef<PyObject>, B: AsRef<PyObject>> AsRef<PyObject> for Either<A, B> {
impl<A, B> AsRef<PyObject> for Either<A, B>
where
A: AsRef<PyObject>,
B: AsRef<PyObject>,
{
#[inline(always)]
fn as_ref(&self) -> &PyObject {
match self {
Expand All @@ -28,7 +36,11 @@ impl<A: AsRef<PyObject>, B: AsRef<PyObject>> AsRef<PyObject> for Either<A, B> {
}
}

impl<A: Into<Self>, B: Into<Self>> From<Either<A, B>> for PyObjectRef {
impl<A, B> From<Either<A, B>> for PyObjectRef
where
A: Into<Self>,
B: Into<Self>,
{
#[inline(always)]
fn from(value: Either<A, B>) -> Self {
match value {
Expand All @@ -38,7 +50,11 @@ impl<A: Into<Self>, B: Into<Self>> From<Either<A, B>> for PyObjectRef {
}
}

impl<A: ToPyObject, B: ToPyObject> ToPyObject for Either<A, B> {
impl<A, B> ToPyObject for Either<A, B>
where
A: ToPyObject,
B: ToPyObject,
{
#[inline(always)]
fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
match self {
Expand Down
4 changes: 1 addition & 3 deletions crates/vm/src/function/getset.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/*! Python `attribute` descriptor class. (PyGetSet)

*/
//! Python `attribute` descriptor class. (PyGetSet)
use crate::{
Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
convert::ToPyResult,
Expand Down
1 change: 1 addition & 0 deletions crates/vm/src/function/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ impl PyMethodDef {
all_methods
}

#[must_use]
const fn const_copy(&self) -> Self {
Self {
name: self.name,
Expand Down
20 changes: 15 additions & 5 deletions crates/vm/src/py_io.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use core::{fmt, ops};
use std::io;

use crate::{
PyObject, PyObjectRef, PyResult, VirtualMachine,
builtins::{PyBaseExceptionRef, PyBytes, PyStr},
common::ascii,
};
use alloc::fmt;
use core::ops;
use std::io;

pub trait Write {
type Error;

fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Self::Error>;
}

Expand All @@ -24,10 +25,12 @@ impl<T> IoWriter<T> {

impl<T> ops::Deref for IoWriter<T> {
type Target = T;

fn deref(&self) -> &T {
&self.0
}
}

impl<T> ops::DerefMut for IoWriter<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
Expand All @@ -39,13 +42,15 @@ where
W: io::Write,
{
type Error = io::Error;

fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
<W as io::Write>::write_fmt(&mut self.0, args)
}
}

impl Write for String {
type Error = fmt::Error;

fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
<Self as fmt::Write>::write_fmt(self, args)
}
Expand All @@ -55,8 +60,10 @@ pub struct PyWriter<'vm>(pub PyObjectRef, pub &'vm VirtualMachine);

impl Write for PyWriter<'_> {
type Error = PyBaseExceptionRef;

fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Self::Error> {
let PyWriter(obj, vm) = self;
let Self(obj, vm) = self;

vm.call_method(obj, "write", (args.to_string(),)).map(drop)
}
}
Expand All @@ -70,13 +77,15 @@ pub fn file_readline(obj: &PyObject, size: Option<usize>, vm: &VirtualMachine) -
vec![vm.ctx.new_str(ascii!("EOF when reading a line")).into()],
)
};

let ret = match_class!(match ret {
s @ PyStr => {
// Use as_wtf8() to handle strings with surrogates (e.g., surrogateescape)
let s_wtf8 = s.as_wtf8();
if s_wtf8.is_empty() {
return Err(eof_err());
}

// '\n' is ASCII, so we can check bytes directly
if s_wtf8.as_bytes().last() == Some(&b'\n') {
let no_nl = &s_wtf8[..s_wtf8.len() - 1];
Expand All @@ -90,13 +99,14 @@ pub fn file_readline(obj: &PyObject, size: Option<usize>, vm: &VirtualMachine) -
if buf.is_empty() {
return Err(eof_err());
}

if buf.last() == Some(&b'\n') {
vm.ctx.new_bytes(buf[..buf.len() - 1].to_owned()).into()
} else {
b.into()
}
}
_ => return Err(vm.new_type_error("object.readline() returned non-string".to_owned())),
_ => return Err(vm.new_type_error("object.readline() returned non-string")),
});
Ok(ret)
}
5 changes: 3 additions & 2 deletions crates/vm/src/py_serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,9 @@ pub struct PyObjectDeserializer<'c> {
}

impl<'c> PyObjectDeserializer<'c> {
pub fn new(vm: &'c VirtualMachine) -> Self {
PyObjectDeserializer { vm }
#[must_use]
pub const fn new(vm: &'c VirtualMachine) -> Self {
Self { vm }
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/vm/src/readline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub enum ReadlineResult {
Line(String),
Eof,
Interrupt,
Io(std::io::Error),
Io(io::Error),
#[cfg(unix)]
OsError(String),
Other(OtherError),
Expand Down
Loading