forked from Rust-related/RustPython
Merge branch 'master' of https://github.com/RustPython/RustPython into extend-socket
This commit is contained in:
2472
Lib/datetime.py
Normal file
2472
Lib/datetime.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -59,10 +59,19 @@ bitflags! {
|
||||
pub type Label = usize;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
/// An indication where the name must be accessed.
|
||||
pub enum NameScope {
|
||||
/// The name will be in the local scope.
|
||||
Local,
|
||||
|
||||
/// The name will be located in scope surrounding the current scope.
|
||||
NonLocal,
|
||||
|
||||
/// The name will be in global scope.
|
||||
Global,
|
||||
|
||||
/// The name will be located in any scope between the current scope and the top scope.
|
||||
Free,
|
||||
}
|
||||
|
||||
/// Transforms a value prior to formatting it.
|
||||
|
||||
@@ -282,8 +282,8 @@ impl<O: OutputStream> Compiler<O> {
|
||||
match symbol.scope {
|
||||
SymbolScope::Global => bytecode::NameScope::Global,
|
||||
SymbolScope::Nonlocal => bytecode::NameScope::NonLocal,
|
||||
SymbolScope::Unknown => bytecode::NameScope::Local,
|
||||
SymbolScope::Local => bytecode::NameScope::Local,
|
||||
SymbolScope::Unknown => bytecode::NameScope::Free,
|
||||
SymbolScope::Local => bytecode::NameScope::Free,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,7 +500,7 @@ impl<O: OutputStream> Compiler<O> {
|
||||
self.compile_jump_if(test, true, end_label)?;
|
||||
self.emit(Instruction::LoadName {
|
||||
name: String::from("AssertionError"),
|
||||
scope: bytecode::NameScope::Local,
|
||||
scope: bytecode::NameScope::Global,
|
||||
});
|
||||
match msg {
|
||||
Some(e) => {
|
||||
@@ -736,7 +736,7 @@ impl<O: OutputStream> Compiler<O> {
|
||||
// Check exception type:
|
||||
self.emit(Instruction::LoadName {
|
||||
name: String::from("isinstance"),
|
||||
scope: bytecode::NameScope::Local,
|
||||
scope: bytecode::NameScope::Global,
|
||||
});
|
||||
self.emit(Instruction::Rotate { amount: 2 });
|
||||
self.compile_expression(exc_type)?;
|
||||
@@ -931,11 +931,11 @@ impl<O: OutputStream> Compiler<O> {
|
||||
|
||||
self.emit(Instruction::LoadName {
|
||||
name: "__name__".to_string(),
|
||||
scope: bytecode::NameScope::Local,
|
||||
scope: bytecode::NameScope::Free,
|
||||
});
|
||||
self.emit(Instruction::StoreName {
|
||||
name: "__module__".to_string(),
|
||||
scope: bytecode::NameScope::Local,
|
||||
scope: bytecode::NameScope::Free,
|
||||
});
|
||||
self.compile_statements(new_body)?;
|
||||
self.emit(Instruction::LoadConst {
|
||||
|
||||
@@ -31,6 +31,9 @@ pub fn statements_to_symbol_table(
|
||||
/// Captures all symbols in the current scope, and has a list of subscopes in this scope.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct SymbolTable {
|
||||
/// The name of this symbol table. Often the name of the class or function.
|
||||
pub name: String,
|
||||
|
||||
/// A set of symbols present on this scope level.
|
||||
pub symbols: IndexMap<String, Symbol>,
|
||||
|
||||
@@ -40,8 +43,9 @@ pub struct SymbolTable {
|
||||
}
|
||||
|
||||
impl SymbolTable {
|
||||
fn new() -> Self {
|
||||
fn new(name: String) -> Self {
|
||||
SymbolTable {
|
||||
name,
|
||||
symbols: Default::default(),
|
||||
sub_tables: vec![],
|
||||
}
|
||||
@@ -209,20 +213,22 @@ impl SymbolTableAnalyzer {
|
||||
if symbol.is_assigned || symbol.is_parameter {
|
||||
symbol.scope = SymbolScope::Local;
|
||||
} else {
|
||||
// TODO: comment this out and make it work properly:
|
||||
/*
|
||||
let found_in_outer_scope = self
|
||||
.tables
|
||||
.iter()
|
||||
.any(|t| t.symbols.contains_key(&symbol.name));
|
||||
// Interesting stuff about the __class__ variable:
|
||||
// https://docs.python.org/3/reference/datamodel.html?highlight=__class__#creating-the-class-object
|
||||
let found_in_outer_scope = (symbol.name == "__class__")
|
||||
|| self
|
||||
.tables
|
||||
.iter()
|
||||
.skip(1)
|
||||
.any(|t| t.symbols.contains_key(&symbol.name));
|
||||
|
||||
if found_in_outer_scope {
|
||||
// Symbol is in some outer scope.
|
||||
|
||||
symbol.is_free = true;
|
||||
} else {
|
||||
// Well, it must be a global then :)
|
||||
// symbol.scope = SymbolScope::Global;
|
||||
symbol.scope = SymbolScope::Global;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,8 +263,7 @@ enum ExpressionContext {
|
||||
|
||||
impl SymbolTableBuilder {
|
||||
fn prepare(&mut self) {
|
||||
let table = SymbolTable::new();
|
||||
self.tables.push(table);
|
||||
self.enter_block("top")
|
||||
}
|
||||
|
||||
fn finish(&mut self) -> Result<SymbolTable, SymbolTableError> {
|
||||
@@ -268,9 +273,9 @@ impl SymbolTableBuilder {
|
||||
Ok(symbol_table)
|
||||
}
|
||||
|
||||
fn enter_block(&mut self) {
|
||||
fn enter_block(&mut self, name: &str) {
|
||||
// let parent = Some(self.tables.last().unwrap().clone());
|
||||
let table = SymbolTable::new();
|
||||
let table = SymbolTable::new(name.to_string());
|
||||
self.tables.push(table);
|
||||
}
|
||||
|
||||
@@ -343,7 +348,7 @@ impl SymbolTableBuilder {
|
||||
if let Some(expression) = returns {
|
||||
self.scan_expression(expression, &ExpressionContext::Load)?;
|
||||
}
|
||||
self.enter_function(args)?;
|
||||
self.enter_function(name, args)?;
|
||||
self.scan_statements(body)?;
|
||||
self.leave_block();
|
||||
}
|
||||
@@ -355,7 +360,7 @@ impl SymbolTableBuilder {
|
||||
decorator_list,
|
||||
} => {
|
||||
self.register_name(name, SymbolUsage::Assigned)?;
|
||||
self.enter_block();
|
||||
self.enter_block(name);
|
||||
self.scan_statements(body)?;
|
||||
self.leave_block();
|
||||
self.scan_expressions(bases, &ExpressionContext::Load)?;
|
||||
@@ -607,7 +612,7 @@ impl SymbolTableBuilder {
|
||||
}
|
||||
}
|
||||
Lambda { args, body } => {
|
||||
self.enter_function(args)?;
|
||||
self.enter_function("lambda", args)?;
|
||||
self.scan_expression(body, &ExpressionContext::Load)?;
|
||||
self.leave_block();
|
||||
}
|
||||
@@ -620,7 +625,7 @@ impl SymbolTableBuilder {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn enter_function(&mut self, args: &ast::Parameters) -> SymbolTableResult {
|
||||
fn enter_function(&mut self, name: &str, args: &ast::Parameters) -> SymbolTableResult {
|
||||
// Evaluate eventual default parameters:
|
||||
self.scan_expressions(&args.defaults, &ExpressionContext::Load)?;
|
||||
for kw_default in &args.kw_defaults {
|
||||
@@ -639,7 +644,7 @@ impl SymbolTableBuilder {
|
||||
self.scan_parameter_annotation(name)?;
|
||||
}
|
||||
|
||||
self.enter_block();
|
||||
self.enter_block(name);
|
||||
|
||||
// Fill scope with parameter names:
|
||||
self.scan_parameters(&args.args)?;
|
||||
|
||||
@@ -73,4 +73,4 @@ print()
|
||||
print('======== dis.dis ========')
|
||||
print()
|
||||
co = compile(source, filename, 'exec')
|
||||
print(dis.dis(co))
|
||||
dis.dis(co)
|
||||
|
||||
15
tests/snippets/arraymodule.py
Normal file
15
tests/snippets/arraymodule.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from array import array
|
||||
|
||||
a1 = array("b", [0, 1, 2, 3])
|
||||
|
||||
assert a1.tobytes() == b"\x00\x01\x02\x03"
|
||||
assert a1[2] == 2
|
||||
|
||||
assert list(a1) == [0, 1, 2, 3]
|
||||
|
||||
a1.reverse()
|
||||
assert a1 == array("B", [3, 2, 1, 0])
|
||||
|
||||
a1.extend([4, 5, 6, 7])
|
||||
|
||||
assert a1 == array("h", [3, 2, 1, 0, 4, 5, 6, 7])
|
||||
@@ -97,14 +97,57 @@ assert 10 // -4 == -3
|
||||
assert -10 // -4 == 2
|
||||
|
||||
assert int() == 0
|
||||
assert int(1) == 1
|
||||
assert int("101", 2) == 5
|
||||
assert int("101", base=2) == 5
|
||||
assert int(1) == 1
|
||||
|
||||
# implied base
|
||||
assert int('1', base=0) == 1
|
||||
assert int('123', base=0) == 123
|
||||
assert int('0b101', base=0) == 5
|
||||
assert int('0B101', base=0) == 5
|
||||
assert int('0o100', base=0) == 64
|
||||
assert int('0O100', base=0) == 64
|
||||
assert int('0xFF', base=0) == 255
|
||||
assert int('0XFF', base=0) == 255
|
||||
with assertRaises(ValueError):
|
||||
int('0xFF', base=10)
|
||||
with assertRaises(ValueError):
|
||||
int('0oFF', base=10)
|
||||
with assertRaises(ValueError):
|
||||
int('0bFF', base=10)
|
||||
with assertRaises(ValueError):
|
||||
int('0bFF', base=10)
|
||||
with assertRaises(ValueError):
|
||||
int(b"F\xc3\xb8\xc3\xb6\xbbB\xc3\xa5r")
|
||||
with assertRaises(ValueError):
|
||||
int(b"F\xc3\xb8\xc3\xb6\xbbB\xc3\xa5r")
|
||||
|
||||
# underscore
|
||||
assert int('0xFF_FF_FF', base=16) == 16_777_215
|
||||
with assertRaises(ValueError):
|
||||
int("_123_")
|
||||
with assertRaises(ValueError):
|
||||
int("123_")
|
||||
with assertRaises(ValueError):
|
||||
int("_123")
|
||||
with assertRaises(ValueError):
|
||||
int("1__23")
|
||||
|
||||
# signed
|
||||
assert int('-123') == -123
|
||||
assert int('+0b101', base=2) == +5
|
||||
|
||||
# trailing spaces
|
||||
assert int(' 1') == 1
|
||||
assert int('1 ') == 1
|
||||
assert int(' 1 ') == 1
|
||||
assert int('10', base=0) == 10
|
||||
|
||||
# type byte, signed, implied base
|
||||
assert int(b' -0XFF ', base=0) == -255
|
||||
|
||||
|
||||
assert int.from_bytes(b'\x00\x10', 'big') == 16
|
||||
assert int.from_bytes(b'\x00\x10', 'little') == 4096
|
||||
assert int.from_bytes(b'\xfc\x00', 'big', signed=True) == -1024
|
||||
@@ -179,4 +222,4 @@ assert (1).__round__(0) == 1
|
||||
assert_raises(TypeError, lambda: (0).__round__(None))
|
||||
assert_raises(TypeError, lambda: (1).__round__(None))
|
||||
assert_raises(TypeError, lambda: (0).__round__(0.0))
|
||||
assert_raises(TypeError, lambda: (1).__round__(0.0))
|
||||
assert_raises(TypeError, lambda: (1).__round__(0.0))
|
||||
|
||||
3812
tests/snippets/stdlib_datetime.py
Normal file
3812
tests/snippets/stdlib_datetime.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,17 @@ def assert_raises(exc_type, expr, msg=None):
|
||||
assert False, failmsg
|
||||
|
||||
|
||||
class assertRaises:
|
||||
def assertRaises(expected, *args, **kw):
|
||||
if not args:
|
||||
assert not kw
|
||||
return _assertRaises(expected)
|
||||
else:
|
||||
f, f_args = args[0], args[1:]
|
||||
with _assertRaises(expected):
|
||||
f(*f_args, **kw)
|
||||
|
||||
|
||||
class _assertRaises:
|
||||
def __init__(self, expected):
|
||||
self.expected = expected
|
||||
self.exception = None
|
||||
|
||||
@@ -95,7 +95,6 @@ fn print_traceback_entry(vm: &VirtualMachine, tb_entry: &PyObjectRef) {
|
||||
print_source_line(filename, lineno.parse().unwrap());
|
||||
} else {
|
||||
println!(" File ??");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -907,6 +907,9 @@ impl Frame {
|
||||
bytecode::NameScope::Local => {
|
||||
self.scope.store_name(vm, name, obj);
|
||||
}
|
||||
bytecode::NameScope::Free => {
|
||||
self.scope.store_name(vm, name, obj);
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
@@ -928,7 +931,8 @@ impl Frame {
|
||||
let optional_value = match name_scope {
|
||||
bytecode::NameScope::Global => self.scope.load_global(vm, name),
|
||||
bytecode::NameScope::NonLocal => self.scope.load_cell(vm, name),
|
||||
bytecode::NameScope::Local => self.scope.load_name(&vm, name),
|
||||
bytecode::NameScope::Local => self.scope.load_local(&vm, name),
|
||||
bytecode::NameScope::Free => self.scope.load_name(&vm, name),
|
||||
};
|
||||
|
||||
let value = match optional_value {
|
||||
|
||||
@@ -273,3 +273,13 @@ macro_rules! flame_guard {
|
||||
let _guard = ::flame::start_guard($name);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! class_or_notimplemented {
|
||||
($vm:expr, $t:ty, $obj:expr) => {
|
||||
match $crate::pyobject::PyObject::downcast::<$t>($obj) {
|
||||
Ok(pyref) => pyref,
|
||||
Err(_) => return Ok($vm.ctx.not_implemented()),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -100,12 +100,12 @@ impl ByteInnerNewOptions {
|
||||
if let OptionalArg::Present(eval) = self.val_option {
|
||||
if let Ok(input) = eval.downcast::<PyString>() {
|
||||
let inner = PyByteInner::from_string(&input.value, enc.as_str(), vm)?;
|
||||
return Ok(inner);
|
||||
Ok(inner)
|
||||
} else {
|
||||
return Err(vm.new_type_error("encoding without a string argument".to_string()));
|
||||
Err(vm.new_type_error("encoding without a string argument".to_string()))
|
||||
}
|
||||
} else {
|
||||
return Err(vm.new_type_error("encoding without a string argument".to_string()));
|
||||
Err(vm.new_type_error("encoding without a string argument".to_string()))
|
||||
}
|
||||
// Only one argument
|
||||
} else {
|
||||
|
||||
@@ -40,6 +40,11 @@ impl IntoPyObject for f64 {
|
||||
Ok(vm.ctx.new_float(self))
|
||||
}
|
||||
}
|
||||
impl IntoPyObject for f32 {
|
||||
fn into_pyobject(self, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(vm.ctx.new_float(f64::from(self)))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromObject for f64 {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
@@ -66,6 +71,18 @@ pub fn try_float(value: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<f6
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! impl_try_from_object_float {
|
||||
($($t:ty),*) => {
|
||||
$(impl TryFromObject for $t {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
PyFloatRef::try_from_object(vm, obj).map(|f| f.to_f64() as $t)
|
||||
}
|
||||
})*
|
||||
};
|
||||
}
|
||||
|
||||
impl_try_from_object_float!(f32, f64);
|
||||
|
||||
fn inner_div(v1: f64, v2: f64, vm: &VirtualMachine) -> PyResult<f64> {
|
||||
if v2 != 0.0 {
|
||||
Ok(v1 / v2)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
use num_bigint::{BigInt, Sign};
|
||||
use num_integer::Integer;
|
||||
use num_traits::{One, Pow, Signed, ToPrimitive, Zero};
|
||||
use num_traits::{Num, One, Pow, Signed, ToPrimitive, Zero};
|
||||
|
||||
use crate::format::FormatSpec;
|
||||
use crate::function::{KwArgs, OptionalArg, PyFuncArgs};
|
||||
@@ -713,7 +714,9 @@ impl IntOptions {
|
||||
fn get_int_value(self, vm: &VirtualMachine) -> PyResult<BigInt> {
|
||||
if let OptionalArg::Present(val) = self.val_options {
|
||||
let base = if let OptionalArg::Present(base) = self.base {
|
||||
if !objtype::isinstance(&val, &vm.ctx.str_type()) {
|
||||
if !(objtype::isinstance(&val, &vm.ctx.str_type())
|
||||
|| objtype::isinstance(&val, &vm.ctx.bytes_type()))
|
||||
{
|
||||
return Err(vm.new_type_error(
|
||||
"int() can't convert non-string with explicit base".to_string(),
|
||||
));
|
||||
@@ -736,21 +739,22 @@ fn int_new(cls: PyClassRef, options: IntOptions, vm: &VirtualMachine) -> PyResul
|
||||
}
|
||||
|
||||
// Casting function:
|
||||
pub fn to_int(vm: &VirtualMachine, obj: &PyObjectRef, mut base: u32) -> PyResult<BigInt> {
|
||||
if base == 0 {
|
||||
base = 10
|
||||
} else if base < 2 || base > 36 {
|
||||
pub fn to_int(vm: &VirtualMachine, obj: &PyObjectRef, base: u32) -> PyResult<BigInt> {
|
||||
if base != 0 && (base < 2 || base > 36) {
|
||||
return Err(vm.new_value_error("int() base must be >= 2 and <= 36, or 0".to_string()));
|
||||
}
|
||||
|
||||
match_class!(obj.clone(),
|
||||
s @ PyString => {
|
||||
i32::from_str_radix(s.as_str().trim(), base)
|
||||
.map(BigInt::from)
|
||||
.map_err(|_|vm.new_value_error(format!(
|
||||
"invalid literal for int() with base {}: '{}'",
|
||||
base, s
|
||||
)))
|
||||
string @ PyString => {
|
||||
let s = string.value.as_str().trim();
|
||||
str_to_int(vm, s, base)
|
||||
},
|
||||
bytes @ PyBytes => {
|
||||
let bytes = bytes.get_value();
|
||||
let s = std::str::from_utf8(bytes)
|
||||
.map(|s| s.trim())
|
||||
.map_err(|e| vm.new_value_error(format!("utf8 decode error: {}", e)))?;
|
||||
str_to_int(vm, s, base)
|
||||
},
|
||||
obj => {
|
||||
let method = vm.get_method_or_type_error(obj.clone(), "__int__", || {
|
||||
@@ -766,6 +770,76 @@ pub fn to_int(vm: &VirtualMachine, obj: &PyObjectRef, mut base: u32) -> PyResult
|
||||
)
|
||||
}
|
||||
|
||||
fn str_to_int(vm: &VirtualMachine, literal: &str, mut base: u32) -> PyResult<BigInt> {
|
||||
let mut buf = validate_literal(vm, literal, base)?;
|
||||
let is_signed = buf.starts_with('+') || buf.starts_with('-');
|
||||
let radix_range = if is_signed { 1..3 } else { 0..2 };
|
||||
let radix_candidate = buf.get(radix_range.clone());
|
||||
|
||||
// try to find base
|
||||
if let Some(radix_candidate) = radix_candidate {
|
||||
if let Some(matched_radix) = detect_base(&radix_candidate) {
|
||||
if base != 0 && base != matched_radix {
|
||||
return Err(invalid_literal(vm, literal, base));
|
||||
} else {
|
||||
base = matched_radix;
|
||||
}
|
||||
|
||||
buf.drain(radix_range);
|
||||
}
|
||||
}
|
||||
|
||||
// base still not found, try to use default
|
||||
if base == 0 {
|
||||
if buf.starts_with('0') {
|
||||
return Err(invalid_literal(vm, literal, base));
|
||||
}
|
||||
|
||||
base = 10;
|
||||
}
|
||||
|
||||
BigInt::from_str_radix(&buf, base).map_err(|_err| invalid_literal(vm, literal, base))
|
||||
}
|
||||
|
||||
fn validate_literal(vm: &VirtualMachine, literal: &str, base: u32) -> PyResult<String> {
|
||||
if literal.starts_with('_') || literal.ends_with('_') {
|
||||
return Err(invalid_literal(vm, literal, base));
|
||||
}
|
||||
|
||||
let mut buf = String::with_capacity(literal.len());
|
||||
let mut last_tok = None;
|
||||
for c in literal.chars() {
|
||||
if !(c.is_ascii_alphanumeric() || c == '_' || c == '+' || c == '-') {
|
||||
return Err(invalid_literal(vm, literal, base));
|
||||
}
|
||||
|
||||
if c == '_' && Some(c) == last_tok {
|
||||
return Err(invalid_literal(vm, literal, base));
|
||||
}
|
||||
|
||||
last_tok = Some(c);
|
||||
buf.push(c);
|
||||
}
|
||||
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn detect_base(literal: &str) -> Option<u32> {
|
||||
match literal {
|
||||
"0x" | "0X" => Some(16),
|
||||
"0o" | "0O" => Some(8),
|
||||
"0b" | "0B" => Some(2),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn invalid_literal(vm: &VirtualMachine, literal: &str, base: u32) -> PyObjectRef {
|
||||
vm.new_value_error(format!(
|
||||
"invalid literal for int() with base {}: '{}'",
|
||||
base, literal
|
||||
))
|
||||
}
|
||||
|
||||
// Retrieve inner int value:
|
||||
pub fn get_value(obj: &PyObjectRef) -> &BigInt {
|
||||
&get_py_int(obj).value
|
||||
|
||||
@@ -471,7 +471,9 @@ pub fn is_valid_slice_arg(
|
||||
match_class!(value,
|
||||
i @ PyInt => Ok(Some(i.as_bigint().clone())),
|
||||
_obj @ PyNone => Ok(None),
|
||||
_=> {return Err(vm.new_type_error("slice indices must be integers or None or have an __index__ method".to_string()));}
|
||||
_=> {
|
||||
Err(vm.new_type_error("slice indices must be integers or None or have an __index__ method".to_string()))
|
||||
}
|
||||
// TODO: check for an __index__ method
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -349,21 +349,35 @@ impl PyString {
|
||||
fn split(
|
||||
&self,
|
||||
pattern: OptionalArg<PyStringRef>,
|
||||
num: OptionalArg<usize>,
|
||||
num: OptionalArg<isize>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyObjectRef {
|
||||
let value = &self.value;
|
||||
let pattern = match pattern {
|
||||
OptionalArg::Present(ref s) => &s.value,
|
||||
OptionalArg::Missing => " ",
|
||||
OptionalArg::Present(ref s) => Some(s.as_str()),
|
||||
OptionalArg::Missing => None,
|
||||
};
|
||||
let num_splits = num.into_option().unwrap_or(-1);
|
||||
let elements: Vec<_> = match (pattern, num_splits.is_negative()) {
|
||||
(Some(pattern), true) => value
|
||||
.split(pattern)
|
||||
.map(|o| vm.ctx.new_str(o.to_string()))
|
||||
.collect(),
|
||||
(Some(pattern), false) => value
|
||||
.splitn(num_splits as usize + 1, pattern)
|
||||
.map(|o| vm.ctx.new_str(o.to_string()))
|
||||
.collect(),
|
||||
(None, true) => value
|
||||
.split(|c: char| c.is_ascii_whitespace())
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(|o| vm.ctx.new_str(o.to_string()))
|
||||
.collect(),
|
||||
(None, false) => value
|
||||
.splitn(num_splits as usize + 1, |c: char| c.is_ascii_whitespace())
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(|o| vm.ctx.new_str(o.to_string()))
|
||||
.collect(),
|
||||
};
|
||||
let num_splits = num
|
||||
.into_option()
|
||||
.unwrap_or_else(|| value.split(pattern).count());
|
||||
let elements = value
|
||||
.splitn(num_splits + 1, pattern)
|
||||
.map(|o| vm.ctx.new_str(o.to_string()))
|
||||
.collect();
|
||||
vm.ctx.new_list(elements)
|
||||
}
|
||||
|
||||
@@ -371,21 +385,35 @@ impl PyString {
|
||||
fn rsplit(
|
||||
&self,
|
||||
pattern: OptionalArg<PyStringRef>,
|
||||
num: OptionalArg<usize>,
|
||||
num: OptionalArg<isize>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyObjectRef {
|
||||
let value = &self.value;
|
||||
let pattern = match pattern {
|
||||
OptionalArg::Present(ref s) => &s.value,
|
||||
OptionalArg::Missing => " ",
|
||||
OptionalArg::Present(ref s) => Some(s.as_str()),
|
||||
OptionalArg::Missing => None,
|
||||
};
|
||||
let num_splits = num.into_option().unwrap_or(-1);
|
||||
let mut elements: Vec<_> = match (pattern, num_splits.is_negative()) {
|
||||
(Some(pattern), true) => value
|
||||
.rsplit(pattern)
|
||||
.map(|o| vm.ctx.new_str(o.to_string()))
|
||||
.collect(),
|
||||
(Some(pattern), false) => value
|
||||
.rsplitn(num_splits as usize + 1, pattern)
|
||||
.map(|o| vm.ctx.new_str(o.to_string()))
|
||||
.collect(),
|
||||
(None, true) => value
|
||||
.rsplit(|c: char| c.is_ascii_whitespace())
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(|o| vm.ctx.new_str(o.to_string()))
|
||||
.collect(),
|
||||
(None, false) => value
|
||||
.rsplitn(num_splits as usize + 1, |c: char| c.is_ascii_whitespace())
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(|o| vm.ctx.new_str(o.to_string()))
|
||||
.collect(),
|
||||
};
|
||||
let num_splits = num
|
||||
.into_option()
|
||||
.unwrap_or_else(|| value.split(pattern).count());
|
||||
let mut elements: Vec<_> = value
|
||||
.rsplitn(num_splits + 1, pattern)
|
||||
.map(|o| vm.ctx.new_str(o.to_string()))
|
||||
.collect();
|
||||
// Unlike Python rsplit, Rust rsplitn returns an iterator that
|
||||
// starts from the end of the string.
|
||||
elements.reverse();
|
||||
|
||||
@@ -312,6 +312,8 @@ fn type_dict_setter(_instance: PyClassRef, _value: PyObjectRef, vm: &VirtualMach
|
||||
|
||||
/// This is the internal get_attr implementation for fast lookup on a class.
|
||||
pub fn class_get_attr(class: &PyClassRef, attr_name: &str) -> Option<PyObjectRef> {
|
||||
flame_guard!(format!("class_get_attr({:?})", attr_name));
|
||||
|
||||
if let Some(item) = class.attributes.borrow().get(attr_name).cloned() {
|
||||
return Some(item);
|
||||
}
|
||||
|
||||
@@ -123,6 +123,7 @@ pub trait NameProtocol {
|
||||
fn load_name(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef>;
|
||||
fn store_name(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef);
|
||||
fn delete_name(&self, vm: &VirtualMachine, name: &str) -> PyResult;
|
||||
fn load_local(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef>;
|
||||
fn load_cell(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef>;
|
||||
fn store_cell(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef);
|
||||
fn load_global(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef>;
|
||||
@@ -142,6 +143,12 @@ impl NameProtocol for Scope {
|
||||
self.load_global(vm, name)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("Scope"))]
|
||||
/// Load a local name. Only check the local dictionary for the given name.
|
||||
fn load_local(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef> {
|
||||
self.get_locals().get_item_option(name, vm).unwrap()
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("Scope"))]
|
||||
fn load_cell(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef> {
|
||||
for dict in self.locals.iter().skip(1) {
|
||||
@@ -170,7 +177,17 @@ impl NameProtocol for Scope {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("Scope"))]
|
||||
/// Load a global name.
|
||||
fn load_global(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef> {
|
||||
// First, take a look in the outmost local scope (the scope at top level)
|
||||
let last_local_dict = self.locals.iter().last();
|
||||
if let Some(local_dict) = last_local_dict {
|
||||
if let Some(value) = local_dict.get_item_option(name, vm).unwrap() {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Now, take a look at the globals or builtins.
|
||||
if let Some(value) = self.globals.get_item_option(name, vm).unwrap() {
|
||||
Some(value)
|
||||
} else {
|
||||
|
||||
392
vm/src/stdlib/array.rs
Normal file
392
vm/src/stdlib/array.rs
Normal file
@@ -0,0 +1,392 @@
|
||||
use crate::function::OptionalArg;
|
||||
use crate::obj::objbytes::PyBytesRef;
|
||||
use crate::obj::objstr::PyStringRef;
|
||||
use crate::obj::objtype::PyClassRef;
|
||||
use crate::obj::{objbool, objiter};
|
||||
use crate::pyobject::{
|
||||
IntoPyObject, PyClassImpl, PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
|
||||
};
|
||||
use crate::VirtualMachine;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::fmt;
|
||||
|
||||
struct ArrayTypeSpecifierError {
|
||||
_priv: (),
|
||||
}
|
||||
|
||||
impl fmt::Display for ArrayTypeSpecifierError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"bad typecode (must be b, B, u, h, H, i, I, l, L, q, Q, f or d)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! def_array_enum {
|
||||
($(($n:ident, $t:ident, $c:literal)),*$(,)?) => {
|
||||
#[derive(Debug)]
|
||||
enum ArrayContentType {
|
||||
$($n(Vec<$t>),)*
|
||||
}
|
||||
|
||||
#[allow(clippy::naive_bytecount, clippy::float_cmp)]
|
||||
impl ArrayContentType {
|
||||
fn from_char(c: char) -> Result<Self, ArrayTypeSpecifierError> {
|
||||
match c {
|
||||
$($c => Ok(ArrayContentType::$n(Vec::new())),)*
|
||||
_ => Err(ArrayTypeSpecifierError { _priv: () }),
|
||||
}
|
||||
}
|
||||
|
||||
fn typecode(&self) -> char {
|
||||
match self {
|
||||
$(ArrayContentType::$n(_) => $c,)*
|
||||
}
|
||||
}
|
||||
|
||||
fn itemsize(&self) -> usize {
|
||||
match self {
|
||||
$(ArrayContentType::$n(_) => std::mem::size_of::<$t>(),)*
|
||||
}
|
||||
}
|
||||
|
||||
fn addr(&self) -> usize {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => v.as_ptr() as usize,)*
|
||||
}
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => v.len(),)*
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
let val = $t::try_from_object(vm, obj)?;
|
||||
v.push(val);
|
||||
})*
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pop(&mut self, i: usize, vm: &VirtualMachine) -> PyResult {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
v.remove(i).into_pyobject(vm)
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
||||
fn insert(&mut self, i: usize, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
let val = $t::try_from_object(vm, obj)?;
|
||||
v.insert(i, val);
|
||||
})*
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn count(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
let val = $t::try_from_object(vm, obj)?;
|
||||
Ok(v.iter().filter(|&&a| a == val).count())
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
||||
fn frombytes(&mut self, b: &[u8]) {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
// safe because every configuration of bytes for the types we
|
||||
// support are valid
|
||||
let ptr = b.as_ptr() as *const $t;
|
||||
let ptr_len = b.len() / std::mem::size_of::<$t>();
|
||||
let slice = unsafe { std::slice::from_raw_parts(ptr, ptr_len) };
|
||||
v.extend_from_slice(slice);
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
||||
fn tobytes(&self) -> Vec<u8> {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
// safe because we're just reading memory as bytes
|
||||
let ptr = v.as_ptr() as *const u8;
|
||||
let ptr_len = v.len() * std::mem::size_of::<$t>();
|
||||
let slice = unsafe { std::slice::from_raw_parts(ptr, ptr_len) };
|
||||
slice.to_vec()
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
||||
fn index(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<usize>> {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => {
|
||||
let val = $t::try_from_object(vm, x)?;
|
||||
Ok(v.iter().position(|&a| a == val))
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
||||
fn reverse(&mut self) {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => v.reverse(),)*
|
||||
}
|
||||
}
|
||||
|
||||
fn getitem(&self, i: usize, vm: &VirtualMachine) -> Option<PyResult> {
|
||||
match self {
|
||||
$(ArrayContentType::$n(v) => v.get(i).map(|x| x.into_pyobject(vm)),)*
|
||||
}
|
||||
}
|
||||
|
||||
fn iter<'a>(&'a self, vm: &'a VirtualMachine) -> impl Iterator<Item = PyResult> + 'a {
|
||||
let mut i = 0;
|
||||
std::iter::from_fn(move || {
|
||||
let ret = self.getitem(i, vm);
|
||||
i += 1;
|
||||
ret
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
def_array_enum!(
|
||||
(SignedByte, i8, 'b'),
|
||||
(UnsignedByte, u8, 'B'),
|
||||
// TODO: support unicode char
|
||||
(SignedShort, i16, 'h'),
|
||||
(UnsignedShort, u16, 'H'),
|
||||
(SignedInt, i16, 'i'),
|
||||
(UnsignedInt, u16, 'I'),
|
||||
(SignedLong, i32, 'l'),
|
||||
(UnsignedLong, u32, 'L'),
|
||||
(SignedLongLong, i64, 'q'),
|
||||
(UnsignedLongLong, u64, 'Q'),
|
||||
(Float, f32, 'f'),
|
||||
(Double, f64, 'd'),
|
||||
);
|
||||
|
||||
#[pyclass]
|
||||
#[derive(Debug)]
|
||||
pub struct PyArray {
|
||||
array: RefCell<ArrayContentType>,
|
||||
}
|
||||
pub type PyArrayRef = PyRef<PyArray>;
|
||||
|
||||
impl PyValue for PyArray {
|
||||
fn class(vm: &VirtualMachine) -> PyClassRef {
|
||||
vm.class("array", "array")
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyArray {
|
||||
#[pymethod(name = "__new__")]
|
||||
fn new(
|
||||
cls: PyClassRef,
|
||||
spec: PyStringRef,
|
||||
init: OptionalArg<PyIterable>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyArrayRef> {
|
||||
let spec = match spec.as_str().len() {
|
||||
1 => spec.as_str().chars().next().unwrap(),
|
||||
_ => {
|
||||
return Err(vm.new_type_error(
|
||||
"array() argument 1 must be a unicode character, not str".to_owned(),
|
||||
))
|
||||
}
|
||||
};
|
||||
let array =
|
||||
ArrayContentType::from_char(spec).map_err(|err| vm.new_value_error(err.to_string()))?;
|
||||
let zelf = PyArray {
|
||||
array: RefCell::new(array),
|
||||
};
|
||||
if let OptionalArg::Present(init) = init {
|
||||
zelf.extend(init, vm)?;
|
||||
}
|
||||
zelf.into_ref_with_type(vm, cls)
|
||||
}
|
||||
|
||||
#[pyproperty]
|
||||
fn typecode(&self, _vm: &VirtualMachine) -> String {
|
||||
self.array.borrow().typecode().to_string()
|
||||
}
|
||||
|
||||
#[pyproperty]
|
||||
fn itemsize(&self, _vm: &VirtualMachine) -> usize {
|
||||
self.array.borrow().itemsize()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn append(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
self.array.borrow_mut().push(x, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn buffer_info(&self, _vm: &VirtualMachine) -> (usize, usize) {
|
||||
let array = self.array.borrow();
|
||||
(array.addr(), array.len())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn count(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
self.array.borrow().count(x, vm)
|
||||
}
|
||||
|
||||
fn idx(&self, i: isize, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
let len = self.array.borrow().len();
|
||||
if len == 0 {
|
||||
return Err(vm.new_index_error("pop from empty array".to_owned()));
|
||||
}
|
||||
let i = if i.is_negative() {
|
||||
len - i.abs() as usize
|
||||
} else {
|
||||
i as usize
|
||||
};
|
||||
if i > len - 1 {
|
||||
return Err(vm.new_index_error("pop index out of range".to_owned()));
|
||||
}
|
||||
Ok(i)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn extend(&self, iter: PyIterable, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let mut array = self.array.borrow_mut();
|
||||
for elem in iter.iter(vm)? {
|
||||
array.push(elem?, vm)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn frombytes(&self, b: PyBytesRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let b = b.get_value();
|
||||
let itemsize = self.array.borrow().itemsize();
|
||||
if b.len() % itemsize != 0 {
|
||||
return Err(vm.new_value_error("bytes length not a multiple of item size".to_owned()));
|
||||
}
|
||||
if b.len() / itemsize > 0 {
|
||||
self.array.borrow_mut().frombytes(&b);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn index(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
self.array
|
||||
.borrow()
|
||||
.index(x, vm)?
|
||||
.ok_or_else(|| vm.new_value_error("x not in array".to_owned()))
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn insert(&self, i: isize, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let i = self.idx(i, vm)?;
|
||||
self.array.borrow_mut().insert(i, x, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn pop(&self, i: OptionalArg<isize>, vm: &VirtualMachine) -> PyResult {
|
||||
let i = self.idx(i.unwrap_or(-1), vm)?;
|
||||
self.array.borrow_mut().pop(i, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn tobytes(&self, _vm: &VirtualMachine) -> Vec<u8> {
|
||||
self.array.borrow().tobytes()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn reverse(&self, _vm: &VirtualMachine) {
|
||||
self.array.borrow_mut().reverse()
|
||||
}
|
||||
|
||||
#[pymethod(name = "__getitem__")]
|
||||
fn getitem(&self, i: isize, vm: &VirtualMachine) -> PyResult {
|
||||
let i = self.idx(i, vm)?;
|
||||
self.array
|
||||
.borrow()
|
||||
.getitem(i, vm)
|
||||
.unwrap_or_else(|| Err(vm.new_index_error("array index out of range".to_owned())))
|
||||
}
|
||||
|
||||
#[pymethod(name = "__eq__")]
|
||||
fn eq(lhs: PyObjectRef, rhs: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
let lhs = class_or_notimplemented!(vm, Self, lhs);
|
||||
let rhs = class_or_notimplemented!(vm, Self, rhs);
|
||||
let lhs = lhs.array.borrow();
|
||||
let rhs = rhs.array.borrow();
|
||||
if lhs.len() != rhs.len() {
|
||||
Ok(vm.new_bool(false))
|
||||
} else {
|
||||
for (a, b) in lhs.iter(vm).zip(rhs.iter(vm)) {
|
||||
let ne = objbool::boolval(vm, vm._ne(a?, b?)?)?;
|
||||
if ne {
|
||||
return Ok(vm.new_bool(false));
|
||||
}
|
||||
}
|
||||
Ok(vm.new_bool(true))
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyArrayIter {
|
||||
PyArrayIter {
|
||||
position: Cell::new(0),
|
||||
array: zelf,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[derive(Debug)]
|
||||
pub struct PyArrayIter {
|
||||
position: Cell<usize>,
|
||||
array: PyArrayRef,
|
||||
}
|
||||
|
||||
impl PyValue for PyArrayIter {
|
||||
fn class(vm: &VirtualMachine) -> PyClassRef {
|
||||
vm.class("array", "arrayiterator")
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyArrayIter {
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
if self.position.get() < self.array.array.borrow().len() {
|
||||
let ret = self
|
||||
.array
|
||||
.array
|
||||
.borrow()
|
||||
.getitem(self.position.get(), vm)
|
||||
.unwrap()?;
|
||||
self.position.set(self.position.get() + 1);
|
||||
Ok(ret)
|
||||
} else {
|
||||
Err(objiter::new_stop_iteration(vm))
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
py_module!(vm, "array", {
|
||||
"array" => PyArray::make_class(&vm.ctx),
|
||||
"arrayiterator" => PyArrayIter::make_class(&vm.ctx),
|
||||
})
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
mod array;
|
||||
#[cfg(feature = "rustpython-parser")]
|
||||
mod ast;
|
||||
mod binascii;
|
||||
@@ -54,7 +55,8 @@ pub type StdlibInitFunc = Box<dyn Fn(&VirtualMachine) -> PyObjectRef>;
|
||||
pub fn get_module_inits() -> HashMap<String, StdlibInitFunc> {
|
||||
#[allow(unused_mut)]
|
||||
let mut modules = hashmap! {
|
||||
"binascii".to_string() => Box::new(binascii::make_module) as StdlibInitFunc,
|
||||
"array".to_string() => Box::new(array::make_module) as StdlibInitFunc,
|
||||
"binascii".to_string() => Box::new(binascii::make_module),
|
||||
"dis".to_string() => Box::new(dis::make_module),
|
||||
"_codecs".to_string() => Box::new(codecs::make_module),
|
||||
"_collections".to_string() => Box::new(collections::make_module),
|
||||
|
||||
@@ -34,7 +34,7 @@ fn symtable_symtable(
|
||||
let symtable =
|
||||
source_to_symtable(&source.value, mode).map_err(|err| vm.new_syntax_error(&err))?;
|
||||
|
||||
let py_symbol_table = to_py_symbol_table("top".to_string(), symtable);
|
||||
let py_symbol_table = to_py_symbol_table(symtable);
|
||||
Ok(py_symbol_table.into_ref(vm))
|
||||
}
|
||||
|
||||
@@ -56,8 +56,8 @@ fn source_to_symtable(
|
||||
Ok(symtable)
|
||||
}
|
||||
|
||||
fn to_py_symbol_table(name: String, symtable: symboltable::SymbolTable) -> PySymbolTable {
|
||||
PySymbolTable { name, symtable }
|
||||
fn to_py_symbol_table(symtable: symboltable::SymbolTable) -> PySymbolTable {
|
||||
PySymbolTable { symtable }
|
||||
}
|
||||
|
||||
type PySymbolTableRef = PyRef<PySymbolTable>;
|
||||
@@ -65,7 +65,6 @@ type PySymbolRef = PyRef<PySymbol>;
|
||||
|
||||
#[pyclass(name = "SymbolTable")]
|
||||
struct PySymbolTable {
|
||||
name: String,
|
||||
symtable: symboltable::SymbolTable,
|
||||
}
|
||||
|
||||
@@ -85,7 +84,7 @@ impl PyValue for PySymbolTable {
|
||||
impl PySymbolTable {
|
||||
#[pymethod(name = "get_name")]
|
||||
fn get_name(&self, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(vm.ctx.new_str(self.name.clone()))
|
||||
Ok(vm.ctx.new_str(self.symtable.name.clone()))
|
||||
}
|
||||
|
||||
#[pymethod(name = "lookup")]
|
||||
@@ -118,11 +117,7 @@ impl PySymbolTable {
|
||||
.symtable
|
||||
.sub_tables
|
||||
.iter()
|
||||
.map(|s| {
|
||||
to_py_symbol_table("bla".to_string(), s.clone())
|
||||
.into_ref(vm)
|
||||
.into_object()
|
||||
})
|
||||
.map(|t| to_py_symbol_table(t.clone()).into_ref(vm).into_object())
|
||||
.collect();
|
||||
Ok(vm.ctx.new_list(children))
|
||||
}
|
||||
|
||||
@@ -534,6 +534,8 @@ impl VirtualMachine {
|
||||
where
|
||||
T: Into<PyFuncArgs>,
|
||||
{
|
||||
flame_guard!(format!("call_method({:?})", method_name));
|
||||
|
||||
// This is only used in the vm for magic methods, which use a greatly simplified attribute lookup.
|
||||
let cls = obj.class();
|
||||
match objtype::class_get_attr(&cls, method_name) {
|
||||
@@ -552,7 +554,6 @@ impl VirtualMachine {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("VirtualMachine"))]
|
||||
fn _invoke(&self, func_ref: &PyObjectRef, args: PyFuncArgs) -> PyResult {
|
||||
vm_trace!("Invoke: {:?} {:?}", func_ref, args);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user