mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Merge branch 'master' into coolreader18/update-deps
This commit is contained in:
33 files changed
+1342
-1154
No files matched your search
Generated
+43
@@ -822,6 +822,8 @@ dependencies = [
|
||||
"num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unic-emoji-char 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1092,6 +1094,42 @@ name = "ucd-util"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unic-char-property"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unic-char-range 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-char-range"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unic-common"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unic-emoji-char"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unic-char-property 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unic-char-range 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unic-ucd-version 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-ucd-version"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unic-common 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.8"
|
||||
@@ -1419,6 +1457,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
||||
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
||||
"checksum unic-char-property 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
|
||||
"checksum unic-char-range 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
|
||||
"checksum unic-common 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
|
||||
"checksum unic-emoji-char 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d"
|
||||
"checksum unic-ucd-version 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
|
||||
"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
|
||||
"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
|
||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||
|
||||
+2
-1
@@ -14,4 +14,5 @@ log="0.4.1"
|
||||
regex="0.2.2"
|
||||
num-bigint = "0.2"
|
||||
num-traits = "0.2"
|
||||
|
||||
unicode-xid = "0.1.0"
|
||||
unic-emoji-char = "0.9.0"
|
||||
+388
-339
@@ -1,12 +1,17 @@
|
||||
//! This module takes care of lexing python source text. This means source
|
||||
//! code is translated into separate tokens.
|
||||
|
||||
extern crate unic_emoji_char;
|
||||
extern crate unicode_xid;
|
||||
|
||||
pub use super::token::Tok;
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::Num;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use unic_emoji_char::is_emoji_presentation;
|
||||
use unicode_xid::UnicodeXID;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
struct IndentationLevel {
|
||||
@@ -300,7 +305,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
while self.is_char() {
|
||||
while self.is_identifier_continuation() {
|
||||
name.push(self.next_char().unwrap());
|
||||
}
|
||||
let end_pos = self.get_pos();
|
||||
@@ -540,10 +545,21 @@ where
|
||||
Ok((start_pos, tok, end_pos))
|
||||
}
|
||||
|
||||
fn is_char(&self) -> bool {
|
||||
match self.chr0 {
|
||||
Some('a'..='z') | Some('A'..='Z') | Some('_') | Some('0'..='9') => true,
|
||||
_ => false,
|
||||
fn is_identifier_start(&self, c: char) -> bool {
|
||||
match c {
|
||||
'_' => true,
|
||||
c => UnicodeXID::is_xid_start(c),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_identifier_continuation(&self) -> bool {
|
||||
if let Some(c) = self.chr0 {
|
||||
match c {
|
||||
'_' | '0'..='9' => true,
|
||||
c => UnicodeXID::is_xid_continue(c),
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,347 +702,380 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
match self.chr0 {
|
||||
Some('0'..='9') => return Some(self.lex_number()),
|
||||
Some('_') | Some('a'..='z') | Some('A'..='Z') => {
|
||||
// Check if we have some character:
|
||||
if let Some(c) = self.chr0 {
|
||||
// First check identifier:
|
||||
if self.is_identifier_start(c) {
|
||||
return Some(self.lex_identifier());
|
||||
}
|
||||
Some('#') => {
|
||||
self.lex_comment();
|
||||
continue;
|
||||
}
|
||||
Some('"') => {
|
||||
return Some(self.lex_string(false, false, false, false));
|
||||
}
|
||||
Some('\'') => {
|
||||
return Some(self.lex_string(false, false, false, false));
|
||||
}
|
||||
Some('=') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::EqEqual, tok_end)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Equal, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some('+') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let Some('=') = self.chr0 {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::PlusEqual, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Plus, tok_end)));
|
||||
}
|
||||
}
|
||||
Some('*') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::StarEqual, tok_end)));
|
||||
}
|
||||
Some('*') => {
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::DoubleStarEqual, tok_end)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::DoubleStar, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Star, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some('/') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::SlashEqual, tok_end)));
|
||||
}
|
||||
Some('/') => {
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::DoubleSlashEqual, tok_end)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::DoubleSlash, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Slash, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some('%') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let Some('=') = self.chr0 {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::PercentEqual, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Percent, tok_end)));
|
||||
}
|
||||
}
|
||||
Some('|') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let Some('=') = self.chr0 {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::VbarEqual, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Vbar, tok_end)));
|
||||
}
|
||||
}
|
||||
Some('^') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let Some('=') = self.chr0 {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::CircumflexEqual, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::CircumFlex, tok_end)));
|
||||
}
|
||||
}
|
||||
Some('&') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let Some('=') = self.chr0 {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::AmperEqual, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Amper, tok_end)));
|
||||
}
|
||||
}
|
||||
Some('-') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::MinusEqual, tok_end)));
|
||||
}
|
||||
Some('>') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Rarrow, tok_end)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Minus, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some('@') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let Some('=') = self.chr0 {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::AtEqual, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::At, tok_end)));
|
||||
}
|
||||
}
|
||||
Some('!') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::NotEqual, tok_end)));
|
||||
}
|
||||
_ => panic!("Invalid token '!'"),
|
||||
}
|
||||
}
|
||||
Some('~') => {
|
||||
return Some(self.eat_single_char(Tok::Tilde));
|
||||
}
|
||||
Some('(') => {
|
||||
let result = self.eat_single_char(Tok::Lpar);
|
||||
self.nesting += 1;
|
||||
return Some(result);
|
||||
}
|
||||
Some(')') => {
|
||||
let result = self.eat_single_char(Tok::Rpar);
|
||||
if self.nesting == 0 {
|
||||
return Some(Err(LexicalError::NestingError));
|
||||
}
|
||||
self.nesting -= 1;
|
||||
return Some(result);
|
||||
}
|
||||
Some('[') => {
|
||||
let result = self.eat_single_char(Tok::Lsqb);
|
||||
self.nesting += 1;
|
||||
return Some(result);
|
||||
}
|
||||
Some(']') => {
|
||||
let result = self.eat_single_char(Tok::Rsqb);
|
||||
if self.nesting == 0 {
|
||||
return Some(Err(LexicalError::NestingError));
|
||||
}
|
||||
self.nesting -= 1;
|
||||
return Some(result);
|
||||
}
|
||||
Some('{') => {
|
||||
let result = self.eat_single_char(Tok::Lbrace);
|
||||
self.nesting += 1;
|
||||
return Some(result);
|
||||
}
|
||||
Some('}') => {
|
||||
let result = self.eat_single_char(Tok::Rbrace);
|
||||
if self.nesting == 0 {
|
||||
return Some(Err(LexicalError::NestingError));
|
||||
}
|
||||
self.nesting -= 1;
|
||||
return Some(result);
|
||||
}
|
||||
Some(':') => {
|
||||
return Some(self.eat_single_char(Tok::Colon));
|
||||
}
|
||||
Some(';') => {
|
||||
return Some(self.eat_single_char(Tok::Semi));
|
||||
}
|
||||
Some('<') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('<') => {
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::LeftShiftEqual, tok_end)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::LeftShift, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::LessEqual, tok_end)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Less, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some('>') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('>') => {
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::RightShiftEqual, tok_end)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::RightShift, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::GreaterEqual, tok_end)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Greater, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(',') => {
|
||||
} else if is_emoji_presentation(c) {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Comma, tok_end)));
|
||||
}
|
||||
Some('.') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let (Some('.'), Some('.')) = (&self.chr0, &self.chr1) {
|
||||
self.next_char();
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Ellipsis, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Dot, tok_end)));
|
||||
}
|
||||
}
|
||||
Some('\n') => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
self.new_line();
|
||||
println!("Emoji: {}", c);
|
||||
return Some(Ok((
|
||||
tok_start,
|
||||
Tok::Name {
|
||||
name: c.to_string(),
|
||||
},
|
||||
tok_end,
|
||||
)));
|
||||
} else {
|
||||
match c {
|
||||
'0'..='9' => return Some(self.lex_number()),
|
||||
'#' => {
|
||||
self.lex_comment();
|
||||
continue;
|
||||
}
|
||||
'"' => {
|
||||
return Some(self.lex_string(false, false, false, false));
|
||||
}
|
||||
'\'' => {
|
||||
return Some(self.lex_string(false, false, false, false));
|
||||
}
|
||||
'=' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::EqEqual, tok_end)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Equal, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
'+' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let Some('=') = self.chr0 {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::PlusEqual, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Plus, tok_end)));
|
||||
}
|
||||
}
|
||||
'*' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::StarEqual, tok_end)));
|
||||
}
|
||||
Some('*') => {
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((
|
||||
tok_start,
|
||||
Tok::DoubleStarEqual,
|
||||
tok_end,
|
||||
)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::DoubleStar, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Star, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
'/' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::SlashEqual, tok_end)));
|
||||
}
|
||||
Some('/') => {
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((
|
||||
tok_start,
|
||||
Tok::DoubleSlashEqual,
|
||||
tok_end,
|
||||
)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::DoubleSlash, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Slash, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
'%' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let Some('=') = self.chr0 {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::PercentEqual, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Percent, tok_end)));
|
||||
}
|
||||
}
|
||||
'|' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let Some('=') = self.chr0 {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::VbarEqual, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Vbar, tok_end)));
|
||||
}
|
||||
}
|
||||
'^' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let Some('=') = self.chr0 {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::CircumflexEqual, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::CircumFlex, tok_end)));
|
||||
}
|
||||
}
|
||||
'&' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let Some('=') = self.chr0 {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::AmperEqual, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Amper, tok_end)));
|
||||
}
|
||||
}
|
||||
'-' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::MinusEqual, tok_end)));
|
||||
}
|
||||
Some('>') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Rarrow, tok_end)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Minus, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
'@' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let Some('=') = self.chr0 {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::AtEqual, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::At, tok_end)));
|
||||
}
|
||||
}
|
||||
'!' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let Some('=') = self.chr0 {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::NotEqual, tok_end)));
|
||||
} else {
|
||||
return Some(Err(LexicalError::UnrecognizedToken { tok: '!' }));
|
||||
}
|
||||
}
|
||||
'~' => {
|
||||
return Some(self.eat_single_char(Tok::Tilde));
|
||||
}
|
||||
'(' => {
|
||||
let result = self.eat_single_char(Tok::Lpar);
|
||||
self.nesting += 1;
|
||||
return Some(result);
|
||||
}
|
||||
')' => {
|
||||
let result = self.eat_single_char(Tok::Rpar);
|
||||
if self.nesting == 0 {
|
||||
return Some(Err(LexicalError::NestingError));
|
||||
}
|
||||
self.nesting -= 1;
|
||||
return Some(result);
|
||||
}
|
||||
'[' => {
|
||||
let result = self.eat_single_char(Tok::Lsqb);
|
||||
self.nesting += 1;
|
||||
return Some(result);
|
||||
}
|
||||
']' => {
|
||||
let result = self.eat_single_char(Tok::Rsqb);
|
||||
if self.nesting == 0 {
|
||||
return Some(Err(LexicalError::NestingError));
|
||||
}
|
||||
self.nesting -= 1;
|
||||
return Some(result);
|
||||
}
|
||||
'{' => {
|
||||
let result = self.eat_single_char(Tok::Lbrace);
|
||||
self.nesting += 1;
|
||||
return Some(result);
|
||||
}
|
||||
'}' => {
|
||||
let result = self.eat_single_char(Tok::Rbrace);
|
||||
if self.nesting == 0 {
|
||||
return Some(Err(LexicalError::NestingError));
|
||||
}
|
||||
self.nesting -= 1;
|
||||
return Some(result);
|
||||
}
|
||||
':' => {
|
||||
return Some(self.eat_single_char(Tok::Colon));
|
||||
}
|
||||
';' => {
|
||||
return Some(self.eat_single_char(Tok::Semi));
|
||||
}
|
||||
'<' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('<') => {
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((
|
||||
tok_start,
|
||||
Tok::LeftShiftEqual,
|
||||
tok_end,
|
||||
)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::LeftShift, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::LessEqual, tok_end)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Less, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
'>' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('>') => {
|
||||
self.next_char();
|
||||
match self.chr0 {
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((
|
||||
tok_start,
|
||||
Tok::RightShiftEqual,
|
||||
tok_end,
|
||||
)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::RightShift, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some('=') => {
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::GreaterEqual, tok_end)));
|
||||
}
|
||||
_ => {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Greater, tok_end)));
|
||||
}
|
||||
}
|
||||
}
|
||||
',' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Comma, tok_end)));
|
||||
}
|
||||
'.' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
if let (Some('.'), Some('.')) = (&self.chr0, &self.chr1) {
|
||||
self.next_char();
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Ellipsis, tok_end)));
|
||||
} else {
|
||||
let tok_end = self.get_pos();
|
||||
return Some(Ok((tok_start, Tok::Dot, tok_end)));
|
||||
}
|
||||
}
|
||||
'\n' => {
|
||||
let tok_start = self.get_pos();
|
||||
self.next_char();
|
||||
let tok_end = self.get_pos();
|
||||
self.new_line();
|
||||
|
||||
// Depending on the nesting level, we emit newline or not:
|
||||
if self.nesting == 0 {
|
||||
self.at_begin_of_line = true;
|
||||
return Some(Ok((tok_start, Tok::Newline, tok_end)));
|
||||
} else {
|
||||
continue;
|
||||
// Depending on the nesting level, we emit newline or not:
|
||||
if self.nesting == 0 {
|
||||
self.at_begin_of_line = true;
|
||||
return Some(Ok((tok_start, Tok::Newline, tok_end)));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
' ' => {
|
||||
// Skip whitespaces
|
||||
self.next_char();
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
let c = self.next_char();
|
||||
return Some(Err(LexicalError::UnrecognizedToken { tok: c.unwrap() }));
|
||||
} // Ignore all the rest..
|
||||
}
|
||||
}
|
||||
Some(' ') => {
|
||||
// Skip whitespaces
|
||||
self.next_char();
|
||||
continue;
|
||||
}
|
||||
None => return None,
|
||||
_ => {
|
||||
let c = self.next_char();
|
||||
return Some(Err(LexicalError::UnrecognizedToken { tok: c.unwrap() }));
|
||||
} // Ignore all the rest..
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -153,7 +153,7 @@ fn get_prompt(vm: &VirtualMachine, prompt_name: &str) -> String {
|
||||
|
||||
fn run_shell(vm: &VirtualMachine) -> PyResult {
|
||||
println!(
|
||||
"Welcome to the magnificent Rust Python {} interpreter",
|
||||
"Welcome to the magnificent Rust Python {} interpreter \u{1f631} \u{1f596}",
|
||||
crate_version!()
|
||||
);
|
||||
let vars = vm.ctx.new_scope();
|
||||
|
||||
@@ -31,7 +31,7 @@ then
|
||||
zip -0 ccov.zip `find . \( -name "rustpython*.gc*" \) -print`
|
||||
|
||||
# Install grcov
|
||||
curl -L https://github.com/mozilla/grcov/releases/download/v0.4.1/grcov-linux-x86_64.tar.bz2 | tar jxf -
|
||||
curl -L https://github.com/mozilla/grcov/releases/download/v0.4.2/grcov-linux-x86_64.tar.bz2 | tar jxf -
|
||||
|
||||
./grcov ccov.zip -s . -t lcov --llvm --branch --ignore-not-existing --ignore-dir "/*" -p "x" > lcov.info
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
x = []
|
||||
x.append(1)
|
||||
@@ -50,3 +50,7 @@ assert 'foo' not in range(10)
|
||||
assert list(reversed(range(5))) == [4, 3, 2, 1, 0]
|
||||
assert list(reversed(range(5, 0, -1))) == [1, 2, 3, 4, 5]
|
||||
assert list(reversed(range(1,10,5))) == [6, 1]
|
||||
|
||||
# range retains the original int refs
|
||||
i = 2**64
|
||||
assert range(i).stop is i
|
||||
@@ -144,3 +144,88 @@ a ^= set([3,4,5])
|
||||
assert a == set([1,2,4,5])
|
||||
with assertRaises(TypeError):
|
||||
a ^= 1
|
||||
|
||||
# frozen set
|
||||
|
||||
assert frozenset([1,2]) == frozenset([1,2])
|
||||
assert not frozenset([1,2,3]) == frozenset([1,2])
|
||||
|
||||
assert frozenset([1,2,3]) >= frozenset([1,2])
|
||||
assert frozenset([1,2]) >= frozenset([1,2])
|
||||
assert not frozenset([1,3]) >= frozenset([1,2])
|
||||
|
||||
assert frozenset([1,2,3]).issuperset(frozenset([1,2]))
|
||||
assert frozenset([1,2]).issuperset(frozenset([1,2]))
|
||||
assert not frozenset([1,3]).issuperset(frozenset([1,2]))
|
||||
|
||||
assert frozenset([1,2,3]) > frozenset([1,2])
|
||||
assert not frozenset([1,2]) > frozenset([1,2])
|
||||
assert not frozenset([1,3]) > frozenset([1,2])
|
||||
|
||||
assert frozenset([1,2]) <= frozenset([1,2,3])
|
||||
assert frozenset([1,2]) <= frozenset([1,2])
|
||||
assert not frozenset([1,3]) <= frozenset([1,2])
|
||||
|
||||
assert frozenset([1,2]).issubset(frozenset([1,2,3]))
|
||||
assert frozenset([1,2]).issubset(frozenset([1,2]))
|
||||
assert not frozenset([1,3]).issubset(frozenset([1,2]))
|
||||
|
||||
assert frozenset([1,2]) < frozenset([1,2,3])
|
||||
assert not frozenset([1,2]) < frozenset([1,2])
|
||||
assert not frozenset([1,3]) < frozenset([1,2])
|
||||
|
||||
a = frozenset([1, 2, 3])
|
||||
assert len(a) == 3
|
||||
b = a.copy()
|
||||
assert b == a
|
||||
|
||||
assert frozenset([1,2,3]).union(frozenset([4,5])) == frozenset([1,2,3,4,5])
|
||||
assert frozenset([1,2,3]).union(frozenset([1,2,3,4,5])) == frozenset([1,2,3,4,5])
|
||||
|
||||
assert frozenset([1,2,3]) | frozenset([4,5]) == frozenset([1,2,3,4,5])
|
||||
assert frozenset([1,2,3]) | frozenset([1,2,3,4,5]) == frozenset([1,2,3,4,5])
|
||||
|
||||
assert frozenset([1,2,3]).intersection(frozenset([1,2])) == frozenset([1,2])
|
||||
assert frozenset([1,2,3]).intersection(frozenset([5,6])) == frozenset([])
|
||||
|
||||
assert frozenset([1,2,3]) & frozenset([4,5]) == frozenset([])
|
||||
assert frozenset([1,2,3]) & frozenset([1,2,3,4,5]) == frozenset([1,2,3])
|
||||
|
||||
assert frozenset([1,2,3]).difference(frozenset([1,2])) == frozenset([3])
|
||||
assert frozenset([1,2,3]).difference(frozenset([5,6])) == frozenset([1,2,3])
|
||||
|
||||
assert frozenset([1,2,3]) - frozenset([4,5]) == frozenset([1,2,3])
|
||||
assert frozenset([1,2,3]) - frozenset([1,2,3,4,5]) == frozenset([])
|
||||
|
||||
assert frozenset([1,2,3]).symmetric_difference(frozenset([1,2])) == frozenset([3])
|
||||
assert frozenset([1,2,3]).symmetric_difference(frozenset([5,6])) == frozenset([1,2,3,5,6])
|
||||
|
||||
assert frozenset([1,2,3]) ^ frozenset([4,5]) == frozenset([1,2,3,4,5])
|
||||
assert frozenset([1,2,3]) ^ frozenset([1,2,3,4,5]) == frozenset([4,5])
|
||||
|
||||
assert_raises(TypeError, lambda: frozenset([[]]))
|
||||
|
||||
# set and frozen set
|
||||
assert frozenset([1,2,3]).union(set([4,5])) == frozenset([1,2,3,4,5])
|
||||
assert set([1,2,3]).union(frozenset([4,5])) == set([1,2,3,4,5])
|
||||
|
||||
assert frozenset([1,2,3]) | set([4,5]) == frozenset([1,2,3,4,5])
|
||||
assert set([1,2,3]) | frozenset([4,5]) == set([1,2,3,4,5])
|
||||
|
||||
assert frozenset([1,2,3]).intersection(set([5,6])) == frozenset([])
|
||||
assert set([1,2,3]).intersection(frozenset([5,6])) == set([])
|
||||
|
||||
assert frozenset([1,2,3]) & set([1,2,3,4,5]) == frozenset([1,2,3])
|
||||
assert set([1,2,3]) & frozenset([1,2,3,4,5]) == set([1,2,3])
|
||||
|
||||
assert frozenset([1,2,3]).difference(set([5,6])) == frozenset([1,2,3])
|
||||
assert set([1,2,3]).difference(frozenset([5,6])) == set([1,2,3])
|
||||
|
||||
assert frozenset([1,2,3]) - set([4,5]) == frozenset([1,2,3])
|
||||
assert set([1,2,3]) - frozenset([4,5]) == frozenset([1,2,3])
|
||||
|
||||
assert frozenset([1,2,3]).symmetric_difference(set([1,2])) == frozenset([3])
|
||||
assert set([1,2,3]).symmetric_difference(frozenset([1,2])) == set([3])
|
||||
|
||||
assert frozenset([1,2,3]) ^ set([4,5]) == frozenset([1,2,3,4,5])
|
||||
assert set([1,2,3]) ^ frozenset([4,5]) == set([1,2,3,4,5])
|
||||
@@ -1,3 +1,5 @@
|
||||
from testutils import assert_raises
|
||||
|
||||
assert "a" == 'a'
|
||||
assert """a""" == "a"
|
||||
assert len(""" " "" " "" """) == 11
|
||||
@@ -124,3 +126,9 @@ assert 'a' <= 'a'
|
||||
assert 'z' > 'b'
|
||||
assert 'z' >= 'b'
|
||||
assert 'a' >= 'a'
|
||||
|
||||
def try_mutate_str():
|
||||
word = "word"
|
||||
word[0] = 'x'
|
||||
|
||||
assert_raises(TypeError, try_mutate_str)
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
# Test the unicode support! 👋
|
||||
|
||||
|
||||
ᚴ=2
|
||||
|
||||
assert ᚴ*8 == 16
|
||||
|
||||
ᚴ="👋"
|
||||
|
||||
c = ᚴ*3
|
||||
|
||||
assert c == '👋👋👋'
|
||||
@@ -1,7 +0,0 @@
|
||||
word = "Python"
|
||||
|
||||
word[0] = "J" # Should raise a error, immutable
|
||||
word[2:] = "Jy" # Should raise a error, immutable
|
||||
|
||||
|
||||
|
||||
+12
-12
@@ -17,7 +17,6 @@ import compile_code
|
||||
|
||||
class _TestType(enum.Enum):
|
||||
functional = 1
|
||||
benchmark = 2
|
||||
|
||||
|
||||
logger = logging.getLogger('tests')
|
||||
@@ -25,7 +24,6 @@ ROOT_DIR = '..'
|
||||
TEST_ROOT = os.path.abspath(os.path.join(ROOT_DIR, 'tests'))
|
||||
TEST_DIRS = {
|
||||
_TestType.functional: os.path.join(TEST_ROOT, 'snippets'),
|
||||
_TestType.benchmark: os.path.join(TEST_ROOT, 'benchmarks'),
|
||||
}
|
||||
CPYTHON_RUNNER_DIR = os.path.abspath(os.path.join(ROOT_DIR, 'py_code_object'))
|
||||
RUSTPYTHON_RUNNER_DIR = os.path.abspath(os.path.join(ROOT_DIR))
|
||||
@@ -65,8 +63,7 @@ def run_via_cpython_bytecode(filename, test_type):
|
||||
|
||||
# Step2: run cpython bytecode:
|
||||
env = os.environ.copy()
|
||||
log_level = 'info' if test_type == _TestType.benchmark else 'debug'
|
||||
env['RUST_LOG'] = '{},cargo=error,jobserver=error'.format(log_level)
|
||||
env['RUST_LOG'] = 'info,cargo=error,jobserver=error'
|
||||
env['RUST_BACKTRACE'] = '1'
|
||||
with pushd(CPYTHON_RUNNER_DIR):
|
||||
subprocess.check_call(['cargo', 'run', bytecode_filename], env=env)
|
||||
@@ -74,15 +71,15 @@ def run_via_cpython_bytecode(filename, test_type):
|
||||
|
||||
def run_via_rustpython(filename, test_type):
|
||||
env = os.environ.copy()
|
||||
log_level = 'info' if test_type == _TestType.benchmark else 'trace'
|
||||
env['RUST_LOG'] = '{},cargo=error,jobserver=error'.format(log_level)
|
||||
env['RUST_LOG'] = 'info,cargo=error,jobserver=error'
|
||||
env['RUST_BACKTRACE'] = '1'
|
||||
|
||||
target = 'release'
|
||||
if env.get('CODE_COVERAGE', 'false') == 'true':
|
||||
subprocess.check_call(
|
||||
['cargo', 'run', filename], env=env)
|
||||
else:
|
||||
subprocess.check_call(
|
||||
['cargo', 'run', '--release', filename], env=env)
|
||||
target = 'debug'
|
||||
binary = os.path.abspath(os.path.join(ROOT_DIR, 'target', target, 'rustpython'))
|
||||
|
||||
subprocess.check_call([binary, filename], env=env)
|
||||
|
||||
|
||||
def create_test_function(cls, filename, method, test_type):
|
||||
@@ -124,4 +121,7 @@ def get_test_files():
|
||||
# @populate('cpython_bytecode')
|
||||
@populate('rustpython')
|
||||
class SampleTestCase(unittest.TestCase):
|
||||
pass
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
subprocess.check_call(['cargo', 'build'])
|
||||
subprocess.check_call(['cargo', 'build', '--release'])
|
||||
+3
-11
@@ -11,7 +11,6 @@ use num_traits::{Signed, ToPrimitive};
|
||||
use crate::compile;
|
||||
use crate::import::import_module;
|
||||
use crate::obj::objbool;
|
||||
use crate::obj::objdict;
|
||||
use crate::obj::objint;
|
||||
use crate::obj::objiter;
|
||||
use crate::obj::objstr::{self, PyStringRef};
|
||||
@@ -29,14 +28,7 @@ use crate::obj::objcode::PyCodeRef;
|
||||
use crate::stdlib::io::io_open;
|
||||
|
||||
fn get_locals(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let d = vm.new_dict();
|
||||
// TODO: implement dict_iter_items?
|
||||
let locals = vm.get_locals();
|
||||
let key_value_pairs = objdict::get_key_value_pairs(&locals);
|
||||
for (key, value) in key_value_pairs {
|
||||
objdict::set_item(&d, vm, &key, &value);
|
||||
}
|
||||
d
|
||||
vm.get_locals()
|
||||
}
|
||||
|
||||
fn dir_locals(vm: &VirtualMachine) -> PyObjectRef {
|
||||
@@ -823,9 +815,9 @@ pub fn builtin_build_class_(vm: &VirtualMachine, mut args: PyFuncArgs) -> PyResu
|
||||
let prepare = vm.get_attribute(metaclass.clone().into_object(), "__prepare__")?;
|
||||
let namespace = vm.invoke(prepare, vec![name_arg.clone(), bases.clone()])?;
|
||||
|
||||
let cells = vm.new_dict();
|
||||
let cells = vm.ctx.new_dict();
|
||||
|
||||
vm.invoke_with_locals(function, cells.clone(), namespace.clone())?;
|
||||
vm.invoke_with_locals(function, cells.clone().into_object(), namespace.clone())?;
|
||||
let class = vm.call_method(
|
||||
metaclass.as_object(),
|
||||
"__call__",
|
||||
|
||||
+9
-7
@@ -119,7 +119,7 @@ impl Scope {
|
||||
}
|
||||
|
||||
pub fn child_scope(&self, ctx: &PyContext) -> Scope {
|
||||
self.child_scope_with_locals(ctx.new_dict())
|
||||
self.child_scope_with_locals(ctx.new_dict().into_object())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ impl NameProtocol for Scope {
|
||||
return Some(value);
|
||||
}
|
||||
|
||||
vm.builtins.get_item(name)
|
||||
vm.get_attribute(vm.builtins.clone(), name).ok()
|
||||
}
|
||||
|
||||
fn load_cell(&self, _vm: &VirtualMachine, name: &str) -> Option<PyObjectRef> {
|
||||
@@ -386,7 +386,7 @@ impl Frame {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BuildMap { size, unpack } => {
|
||||
let map_obj = vm.ctx.new_dict();
|
||||
let map_obj = vm.ctx.new_dict().into_object();
|
||||
for _x in 0..*size {
|
||||
let obj = self.pop_value();
|
||||
if *unpack {
|
||||
@@ -413,7 +413,7 @@ impl Frame {
|
||||
if x.is(&vm.ctx.none()) {
|
||||
None
|
||||
} else if let Some(i) = x.payload::<PyInt>() {
|
||||
Some(i.value.clone())
|
||||
Some(i.as_bigint().clone())
|
||||
} else {
|
||||
panic!("Expect Int or None as BUILD_SLICE arguments")
|
||||
}
|
||||
@@ -572,7 +572,7 @@ impl Frame {
|
||||
let annotations = if flags.contains(bytecode::FunctionOpArg::HAS_ANNOTATIONS) {
|
||||
self.pop_value()
|
||||
} else {
|
||||
vm.new_dict()
|
||||
vm.ctx.new_dict().into_object()
|
||||
};
|
||||
|
||||
let defaults = if flags.contains(bytecode::FunctionOpArg::HAS_DEFAULTS) {
|
||||
@@ -839,8 +839,10 @@ impl Frame {
|
||||
let module = vm.import(module)?;
|
||||
|
||||
// Grab all the names from the module and put them in the context
|
||||
for (k, v) in module.get_key_value_pairs().iter() {
|
||||
self.scope.store_name(&vm, &objstr::get_value(k), v.clone());
|
||||
if let Some(dict) = &module.dict {
|
||||
for (k, v) in dict.get_key_value_pairs().iter() {
|
||||
self.scope.store_name(&vm, &objstr::get_value(k), v.clone());
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
@@ -247,6 +247,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for KwArgs<T> {
|
||||
type Item = (String, T);
|
||||
type IntoIter = std::collections::hash_map::IntoIter<String, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of positional argument values.
|
||||
///
|
||||
/// A built-in function with a `Args` parameter is analagous to a Python
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ fn import_uncached_module(vm: &VirtualMachine, current_path: PathBuf, module: &s
|
||||
|
||||
let attrs = vm.ctx.new_dict();
|
||||
attrs.set_item(&vm.ctx, "__name__", vm.new_str(module.to_string()));
|
||||
vm.run_code_obj(code_obj, Scope::new(None, attrs.clone()))?;
|
||||
vm.run_code_obj(code_obj, Scope::new(None, attrs.clone().into_object()))?;
|
||||
Ok(vm.ctx.new_module(module, attrs))
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ pub fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<bool> {
|
||||
Ok(if let Ok(f) = vm.get_method(obj.clone(), "__bool__") {
|
||||
let bool_res = vm.invoke(f, PyFuncArgs::default())?;
|
||||
match bool_res.payload::<PyInt>() {
|
||||
Some(i) => !i.value.is_zero(),
|
||||
Some(i) => !i.as_bigint().is_zero(),
|
||||
None => return Err(vm.new_type_error(String::from("TypeError"))),
|
||||
}
|
||||
} else {
|
||||
@@ -59,7 +59,7 @@ pub fn not(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult {
|
||||
|
||||
// Retrieve inner int value:
|
||||
pub fn get_value(obj: &PyObjectRef) -> bool {
|
||||
!obj.payload::<PyInt>().unwrap().value.is_zero()
|
||||
!obj.payload::<PyInt>().unwrap().as_bigint().is_zero()
|
||||
}
|
||||
|
||||
fn bool_repr(vm: &VirtualMachine, args: PyFuncArgs) -> Result<PyObjectRef, PyObjectRef> {
|
||||
|
||||
+63
-47
@@ -3,9 +3,9 @@ use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::function::{OptionalArg, PyFuncArgs};
|
||||
use crate::function::{KwArgs, OptionalArg};
|
||||
use crate::pyobject::{
|
||||
PyAttributes, PyContext, PyIteratorValue, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
|
||||
DictProtocol, PyAttributes, PyContext, PyIteratorValue, PyObjectRef, PyRef, PyResult, PyValue,
|
||||
};
|
||||
use crate::vm::{ReprGuard, VirtualMachine};
|
||||
|
||||
@@ -124,57 +124,48 @@ pub fn py_dict_to_attributes(dict: &PyObjectRef) -> PyAttributes {
|
||||
attrs
|
||||
}
|
||||
|
||||
pub fn attributes_to_py_dict(vm: &VirtualMachine, attributes: PyAttributes) -> PyResult {
|
||||
let dict = vm.ctx.new_dict();
|
||||
for (key, value) in attributes {
|
||||
let key = vm.ctx.new_str(key);
|
||||
set_item(&dict, vm, &key, &value);
|
||||
}
|
||||
Ok(dict)
|
||||
}
|
||||
|
||||
// Python dict methods:
|
||||
fn dict_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(
|
||||
vm,
|
||||
args,
|
||||
required = [(_ty, Some(vm.ctx.type_type()))],
|
||||
optional = [(dict_obj, None)]
|
||||
);
|
||||
let dict = vm.ctx.new_dict();
|
||||
if let Some(dict_obj) = dict_obj {
|
||||
if objtype::isinstance(&dict_obj, &vm.ctx.dict_type()) {
|
||||
for (needle, value) in get_key_value_pairs(&dict_obj) {
|
||||
set_item(&dict, vm, &needle, &value);
|
||||
}
|
||||
} else {
|
||||
let iter = objiter::get_iter(vm, dict_obj)?;
|
||||
loop {
|
||||
fn err(vm: &VirtualMachine) -> PyObjectRef {
|
||||
vm.new_type_error("Iterator must have exactly two elements".to_string())
|
||||
impl PyDictRef {
|
||||
fn new(
|
||||
_class: PyClassRef, // TODO Support subclasses of int.
|
||||
dict_obj: OptionalArg<PyObjectRef>,
|
||||
kwargs: KwArgs,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyDictRef> {
|
||||
let dict = vm.ctx.new_dict();
|
||||
if let OptionalArg::Present(dict_obj) = dict_obj {
|
||||
if objtype::isinstance(&dict_obj, &vm.ctx.dict_type()) {
|
||||
for (needle, value) in get_key_value_pairs(&dict_obj) {
|
||||
set_item(dict.as_object(), vm, &needle, &value);
|
||||
}
|
||||
let element = match objiter::get_next_object(vm, &iter)? {
|
||||
Some(obj) => obj,
|
||||
None => break,
|
||||
};
|
||||
let elem_iter = objiter::get_iter(vm, &element)?;
|
||||
let needle = objiter::get_next_object(vm, &elem_iter)?.ok_or_else(|| err(vm))?;
|
||||
let value = objiter::get_next_object(vm, &elem_iter)?.ok_or_else(|| err(vm))?;
|
||||
if objiter::get_next_object(vm, &elem_iter)?.is_some() {
|
||||
return Err(err(vm));
|
||||
} else {
|
||||
let iter = objiter::get_iter(vm, &dict_obj)?;
|
||||
loop {
|
||||
fn err(vm: &VirtualMachine) -> PyObjectRef {
|
||||
vm.new_type_error("Iterator must have exactly two elements".to_string())
|
||||
}
|
||||
let element = match objiter::get_next_object(vm, &iter)? {
|
||||
Some(obj) => obj,
|
||||
None => break,
|
||||
};
|
||||
let elem_iter = objiter::get_iter(vm, &element)?;
|
||||
let needle =
|
||||
objiter::get_next_object(vm, &elem_iter)?.ok_or_else(|| err(vm))?;
|
||||
let value = objiter::get_next_object(vm, &elem_iter)?.ok_or_else(|| err(vm))?;
|
||||
if objiter::get_next_object(vm, &elem_iter)?.is_some() {
|
||||
return Err(err(vm));
|
||||
}
|
||||
set_item(dict.as_object(), vm, &needle, &value);
|
||||
}
|
||||
set_item(&dict, vm, &needle, &value);
|
||||
}
|
||||
}
|
||||
for (needle, value) in kwargs.into_iter() {
|
||||
let py_needle = vm.new_str(needle);
|
||||
set_item(&dict.as_object(), vm, &py_needle, &value);
|
||||
}
|
||||
Ok(dict)
|
||||
}
|
||||
for (needle, value) in args.kwargs {
|
||||
let py_needle = vm.new_str(needle);
|
||||
set_item(&dict, vm, &py_needle, &value);
|
||||
}
|
||||
Ok(dict)
|
||||
}
|
||||
|
||||
impl PyDictRef {
|
||||
fn bool(self, _vm: &VirtualMachine) -> bool {
|
||||
!self.entries.borrow().is_empty()
|
||||
}
|
||||
@@ -302,6 +293,31 @@ impl PyDictRef {
|
||||
}
|
||||
}
|
||||
|
||||
impl DictProtocol for PyDictRef {
|
||||
fn contains_key(&self, k: &str) -> bool {
|
||||
content_contains_key_str(&self.entries.borrow(), k)
|
||||
}
|
||||
|
||||
fn get_item(&self, k: &str) -> Option<PyObjectRef> {
|
||||
content_get_key_str(&self.entries.borrow(), k)
|
||||
}
|
||||
|
||||
fn get_key_value_pairs(&self) -> Vec<(PyObjectRef, PyObjectRef)> {
|
||||
get_key_value_pairs(self.as_object())
|
||||
}
|
||||
|
||||
// Item set/get:
|
||||
fn set_item(&self, ctx: &PyContext, key: &str, v: PyObjectRef) {
|
||||
let key = ctx.new_str(key.to_string());
|
||||
set_item_in_content(&mut self.entries.borrow_mut(), &key, &v);
|
||||
}
|
||||
|
||||
fn del_item(&self, key: &str) {
|
||||
let mut elements = get_mut_elements(self.as_object());
|
||||
elements.remove(key).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
extend_class!(context, &context.dict_type, {
|
||||
"__bool__" => context.new_rustfunc(PyDictRef::bool),
|
||||
@@ -310,7 +326,7 @@ pub fn init(context: &PyContext) {
|
||||
"__delitem__" => context.new_rustfunc(PyDictRef::delitem),
|
||||
"__getitem__" => context.new_rustfunc(PyDictRef::getitem),
|
||||
"__iter__" => context.new_rustfunc(PyDictRef::iter),
|
||||
"__new__" => context.new_rustfunc(dict_new),
|
||||
"__new__" => context.new_rustfunc(PyDictRef::new),
|
||||
"__repr__" => context.new_rustfunc(PyDictRef::repr),
|
||||
"__setitem__" => context.new_rustfunc(PyDictRef::setitem),
|
||||
"clear" => context.new_rustfunc(PyDictRef::clear),
|
||||
|
||||
@@ -32,7 +32,7 @@ fn enumerate_new(
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyEnumerateRef> {
|
||||
let counter = match start {
|
||||
OptionalArg::Present(start) => start.value.clone(),
|
||||
OptionalArg::Present(start) => start.as_bigint().clone(),
|
||||
OptionalArg::Missing => BigInt::zero(),
|
||||
};
|
||||
|
||||
|
||||
+12
-2
@@ -1,3 +1,4 @@
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use num_bigint::{BigInt, ToBigInt};
|
||||
@@ -18,8 +19,13 @@ use crate::obj::objtype::PyClassRef;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PyInt {
|
||||
// TODO: shouldn't be public
|
||||
pub value: BigInt,
|
||||
value: BigInt,
|
||||
}
|
||||
|
||||
impl fmt::Display for PyInt {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
BigInt::fmt(&self.value, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub type PyIntRef = PyRef<PyInt>;
|
||||
@@ -28,6 +34,10 @@ impl PyInt {
|
||||
pub fn new<T: Into<BigInt>>(i: T) -> Self {
|
||||
PyInt { value: i.into() }
|
||||
}
|
||||
|
||||
pub fn as_bigint(&self) -> &BigInt {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoPyObject for BigInt {
|
||||
|
||||
+11
-15
@@ -1,12 +1,10 @@
|
||||
use crate::obj::objstr::PyStringRef;
|
||||
use crate::obj::objtype::PyClassRef;
|
||||
use crate::pyobject::{DictProtocol, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::pyobject::{DictProtocol, PyContext, PyRef, PyResult, PyValue};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PyModule {
|
||||
pub name: String,
|
||||
pub dict: PyObjectRef,
|
||||
}
|
||||
pub type PyModuleRef = PyRef<PyModule>;
|
||||
|
||||
@@ -18,23 +16,21 @@ impl PyValue for PyModule {
|
||||
|
||||
impl PyModuleRef {
|
||||
fn dir(self: PyModuleRef, vm: &VirtualMachine) -> PyResult {
|
||||
let keys = self
|
||||
.dict
|
||||
.get_key_value_pairs()
|
||||
.iter()
|
||||
.map(|(k, _v)| k.clone())
|
||||
.collect();
|
||||
Ok(vm.ctx.new_list(keys))
|
||||
}
|
||||
|
||||
fn set_attr(self, attr: PyStringRef, value: PyObjectRef, vm: &VirtualMachine) {
|
||||
self.dict.set_item(&vm.ctx, &attr.value, value)
|
||||
if let Some(dict) = &self.into_object().dict {
|
||||
let keys = dict
|
||||
.get_key_value_pairs()
|
||||
.iter()
|
||||
.map(|(k, _v)| k.clone())
|
||||
.collect();
|
||||
Ok(vm.ctx.new_list(keys))
|
||||
} else {
|
||||
panic!("Modules should definitely have a dict.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
extend_class!(&context, &context.module_type, {
|
||||
"__dir__" => context.new_rustfunc(PyModuleRef::dir),
|
||||
"__setattr__" => context.new_rustfunc(PyModuleRef::set_attr)
|
||||
});
|
||||
}
|
||||
+14
-24
@@ -1,5 +1,5 @@
|
||||
use super::objdict::{self, PyDictRef};
|
||||
use super::objlist::PyList;
|
||||
use super::objmodule::PyModule;
|
||||
use super::objstr::{self, PyStringRef};
|
||||
use super::objtype;
|
||||
use crate::function::PyFuncArgs;
|
||||
@@ -23,11 +23,12 @@ impl PyValue for PyInstance {
|
||||
pub fn new_instance(vm: &VirtualMachine, mut args: PyFuncArgs) -> PyResult {
|
||||
// more or less __new__ operator
|
||||
let cls = PyClassRef::try_from_object(vm, args.shift())?;
|
||||
Ok(if cls.is(&vm.ctx.object) {
|
||||
PyObject::new_without_dict(PyInstance, cls)
|
||||
let dict = if cls.is(&vm.ctx.object) {
|
||||
None
|
||||
} else {
|
||||
PyObject::new(PyInstance, cls)
|
||||
})
|
||||
Some(vm.ctx.new_dict())
|
||||
};
|
||||
Ok(PyObject::new(PyInstance, cls, dict))
|
||||
}
|
||||
|
||||
fn object_eq(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
@@ -114,7 +115,7 @@ fn object_setattr(
|
||||
}
|
||||
|
||||
if let Some(ref dict) = obj.clone().dict {
|
||||
dict.borrow_mut().insert(attr_name.value.clone(), value);
|
||||
dict.set_item(&vm.ctx, &attr_name.value, value);
|
||||
Ok(())
|
||||
} else {
|
||||
let type_name = objtype::get_type_name(obj.type_ref());
|
||||
@@ -135,7 +136,7 @@ fn object_delattr(obj: PyObjectRef, attr_name: PyStringRef, vm: &VirtualMachine)
|
||||
}
|
||||
|
||||
if let Some(ref dict) = obj.dict {
|
||||
dict.borrow_mut().remove(&attr_name.value);
|
||||
dict.del_item(&attr_name.value);
|
||||
Ok(())
|
||||
} else {
|
||||
let type_name = objtype::get_type_name(obj.type_ref());
|
||||
@@ -227,13 +228,9 @@ fn object_class_setter(
|
||||
Err(vm.new_type_error(format!("can't change class of type '{}'", type_repr)))
|
||||
}
|
||||
|
||||
fn object_dict(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
if let Some(ref dict) = args.args[0].dict {
|
||||
let new_dict = vm.new_dict();
|
||||
for (attr, value) in dict.borrow().iter() {
|
||||
new_dict.set_item(&vm.ctx, &attr, value.clone());
|
||||
}
|
||||
Ok(new_dict)
|
||||
fn object_dict(object: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyDictRef> {
|
||||
if let Some(ref dict) = object.dict {
|
||||
Ok(dict.clone())
|
||||
} else {
|
||||
Err(vm.new_type_error("TypeError: no dictionary.".to_string()))
|
||||
}
|
||||
@@ -273,15 +270,8 @@ fn object_getattribute(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
}
|
||||
|
||||
fn object_getattr(obj: &PyObjectRef, attr_name: &str) -> Option<PyObjectRef> {
|
||||
// TODO:
|
||||
// This is an all kinds of wrong work-around for the temporary difference in
|
||||
// shape between modules and object. It will disappear once that is fixed.
|
||||
if let Some(PyModule { ref dict, .. }) = obj.payload::<PyModule>() {
|
||||
return dict.get_item(attr_name);
|
||||
}
|
||||
|
||||
if let Some(ref dict) = obj.dict {
|
||||
dict.borrow().get(attr_name).cloned()
|
||||
dict.get_item(attr_name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -293,8 +283,8 @@ pub fn get_attributes(obj: &PyObjectRef) -> PyAttributes {
|
||||
|
||||
// Get instance attributes:
|
||||
if let Some(dict) = &obj.dict {
|
||||
for (name, value) in dict.borrow().iter() {
|
||||
attributes.insert(name.to_string(), value.clone());
|
||||
for (key, value) in objdict::get_key_value_pairs(dict.as_object()) {
|
||||
attributes.insert(key.to_string(), value.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@ impl<'a> PropertyBuilder<'a> {
|
||||
deleter: None,
|
||||
};
|
||||
|
||||
PyObject::new(payload, self.ctx.property_type())
|
||||
PyObject::new(payload, self.ctx.property_type(), None)
|
||||
} else {
|
||||
let payload = PyReadOnlyProperty {
|
||||
getter: self.getter.expect(
|
||||
@@ -208,7 +208,7 @@ impl<'a> PropertyBuilder<'a> {
|
||||
),
|
||||
};
|
||||
|
||||
PyObject::new(payload, self.ctx.readonly_property_type())
|
||||
PyObject::new(payload, self.ctx.readonly_property_type(), None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+161
-231
@@ -3,25 +3,21 @@ use std::ops::Mul;
|
||||
|
||||
use num_bigint::{BigInt, Sign};
|
||||
use num_integer::Integer;
|
||||
use num_traits::{One, Signed, ToPrimitive, Zero};
|
||||
use num_traits::{One, Signed, Zero};
|
||||
|
||||
use crate::function::{OptionalArg, PyFuncArgs};
|
||||
use crate::pyobject::{
|
||||
Either, PyContext, PyIteratorValue, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
|
||||
};
|
||||
use crate::pyobject::{Either, PyContext, PyIteratorValue, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
use super::objint::{self, PyInt, PyIntRef};
|
||||
use super::objint::{PyInt, PyIntRef};
|
||||
use super::objslice::PySliceRef;
|
||||
use super::objtype::{self, PyClassRef};
|
||||
use super::objtype::PyClassRef;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PyRange {
|
||||
// Unfortunately Rust's built in range type doesn't support things like indexing
|
||||
// or ranges where start > end so we need to roll our own.
|
||||
pub start: BigInt,
|
||||
pub stop: BigInt,
|
||||
pub step: BigInt,
|
||||
pub start: PyIntRef,
|
||||
pub stop: PyIntRef,
|
||||
pub step: PyIntRef,
|
||||
}
|
||||
|
||||
impl PyValue for PyRange {
|
||||
@@ -31,71 +27,38 @@ impl PyValue for PyRange {
|
||||
}
|
||||
|
||||
impl PyRange {
|
||||
#[inline]
|
||||
pub fn try_len(&self) -> Option<usize> {
|
||||
match self.step.sign() {
|
||||
Sign::Plus if self.start < self.stop => ((&self.stop - &self.start - 1usize)
|
||||
/ &self.step)
|
||||
.to_usize()
|
||||
.map(|sz| sz + 1),
|
||||
Sign::Minus if self.start > self.stop => ((&self.start - &self.stop - 1usize)
|
||||
/ (-&self.step))
|
||||
.to_usize()
|
||||
.map(|sz| sz + 1),
|
||||
_ => Some(0),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.try_len().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn offset(&self, value: &BigInt) -> Option<BigInt> {
|
||||
match self.step.sign() {
|
||||
Sign::Plus if *value >= self.start && *value < self.stop => Some(value - &self.start),
|
||||
Sign::Minus if *value <= self.start && *value > self.stop => Some(&self.start - value),
|
||||
let start = self.start.as_bigint();
|
||||
let stop = self.stop.as_bigint();
|
||||
let step = self.step.as_bigint();
|
||||
match step.sign() {
|
||||
Sign::Plus if value >= start && value < stop => Some(value - start),
|
||||
Sign::Minus if value <= self.start.as_bigint() && value > stop => Some(start - value),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains(&self, value: &BigInt) -> bool {
|
||||
match self.offset(value) {
|
||||
Some(ref offset) => offset.is_multiple_of(&self.step),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn index_of(&self, value: &BigInt) -> Option<BigInt> {
|
||||
let step = self.step.as_bigint();
|
||||
match self.offset(value) {
|
||||
Some(ref offset) if offset.is_multiple_of(&self.step) => {
|
||||
Some((offset / &self.step).abs())
|
||||
}
|
||||
Some(ref offset) if offset.is_multiple_of(step) => Some((offset / step).abs()),
|
||||
Some(_) | None => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn count(&self, value: &BigInt) -> usize {
|
||||
if self.index_of(value).is_some() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
(self.start <= self.stop && self.step.is_negative())
|
||||
|| (self.start >= self.stop && self.step.is_positive())
|
||||
let start = self.start.as_bigint();
|
||||
let stop = self.stop.as_bigint();
|
||||
let step = self.step.as_bigint();
|
||||
(start <= stop && step.is_negative()) || (start >= stop && step.is_positive())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn forward(&self) -> bool {
|
||||
self.start < self.stop
|
||||
self.start.as_bigint() < self.stop.as_bigint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -103,50 +66,20 @@ impl PyRange {
|
||||
where
|
||||
&'a BigInt: Mul<T, Output = BigInt>,
|
||||
{
|
||||
let result = &self.start + &self.step * index;
|
||||
let start = self.start.as_bigint();
|
||||
let stop = self.stop.as_bigint();
|
||||
let step = self.step.as_bigint();
|
||||
|
||||
if (self.forward() && !self.is_empty() && result < self.stop)
|
||||
|| (!self.forward() && !self.is_empty() && result > self.stop)
|
||||
let result = start + step * index;
|
||||
|
||||
if (self.forward() && !self.is_empty() && &result < stop)
|
||||
|| (!self.forward() && !self.is_empty() && &result > stop)
|
||||
{
|
||||
Some(result)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn reversed(&self) -> Self {
|
||||
// compute the last element that is actually contained within the range
|
||||
// this is the new start
|
||||
let remainder = ((&self.stop - &self.start) % &self.step).abs();
|
||||
let start = if remainder.is_zero() {
|
||||
&self.stop - &self.step
|
||||
} else {
|
||||
&self.stop - &remainder
|
||||
};
|
||||
|
||||
match self.step.sign() {
|
||||
Sign::Plus => PyRange {
|
||||
start,
|
||||
stop: &self.start - 1,
|
||||
step: -&self.step,
|
||||
},
|
||||
Sign::Minus => PyRange {
|
||||
start,
|
||||
stop: &self.start + 1,
|
||||
step: -&self.step,
|
||||
},
|
||||
Sign::NoSign => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn repr(&self) -> String {
|
||||
if self.step == BigInt::one() {
|
||||
format!("range({}, {})", self.start, self.stop)
|
||||
} else {
|
||||
format!("range({}, {}, {})", self.start, self.stop, self.step)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value(obj: &PyObjectRef) -> PyRange {
|
||||
@@ -165,20 +98,20 @@ pub fn init(context: &PyContext) {
|
||||
When step is given, it specifies the increment (or decrement).";
|
||||
|
||||
extend_class!(context, range_type, {
|
||||
"__bool__" => context.new_rustfunc(range_bool),
|
||||
"__contains__" => context.new_rustfunc(range_contains),
|
||||
"__bool__" => context.new_rustfunc(PyRangeRef::bool),
|
||||
"__contains__" => context.new_rustfunc(PyRangeRef::contains),
|
||||
"__doc__" => context.new_str(range_doc.to_string()),
|
||||
"__getitem__" => context.new_rustfunc(PyRangeRef::getitem),
|
||||
"__iter__" => context.new_rustfunc(range_iter),
|
||||
"__len__" => context.new_rustfunc(range_len),
|
||||
"__iter__" => context.new_rustfunc(PyRangeRef::iter),
|
||||
"__len__" => context.new_rustfunc(PyRangeRef::len),
|
||||
"__new__" => context.new_rustfunc(range_new),
|
||||
"__repr__" => context.new_rustfunc(range_repr),
|
||||
"__reversed__" => context.new_rustfunc(range_reversed),
|
||||
"count" => context.new_rustfunc(range_count),
|
||||
"index" => context.new_rustfunc(range_index),
|
||||
"start" => context.new_property(range_start),
|
||||
"step" => context.new_property(range_step),
|
||||
"stop" => context.new_property(range_stop)
|
||||
"__repr__" => context.new_rustfunc(PyRangeRef::repr),
|
||||
"__reversed__" => context.new_rustfunc(PyRangeRef::reversed),
|
||||
"count" => context.new_rustfunc(PyRangeRef::count),
|
||||
"index" => context.new_rustfunc(PyRangeRef::index),
|
||||
"start" => context.new_property(PyRangeRef::start),
|
||||
"stop" => context.new_property(PyRangeRef::stop),
|
||||
"step" => context.new_property(PyRangeRef::step),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -187,9 +120,9 @@ type PyRangeRef = PyRef<PyRange>;
|
||||
impl PyRangeRef {
|
||||
fn new(cls: PyClassRef, stop: PyIntRef, vm: &VirtualMachine) -> PyResult<PyRangeRef> {
|
||||
PyRange {
|
||||
start: Zero::zero(),
|
||||
stop: stop.value.clone(),
|
||||
step: One::one(),
|
||||
start: PyInt::new(BigInt::zero()).into_ref(vm),
|
||||
stop: stop.clone(),
|
||||
step: PyInt::new(BigInt::one()).into_ref(vm),
|
||||
}
|
||||
.into_ref_with_type(vm, cls)
|
||||
}
|
||||
@@ -202,29 +135,138 @@ impl PyRangeRef {
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyRangeRef> {
|
||||
PyRange {
|
||||
start: start.value.clone(),
|
||||
stop: stop.value.clone(),
|
||||
start: start,
|
||||
stop: stop,
|
||||
step: step
|
||||
.into_option()
|
||||
.map(|i| i.value.clone())
|
||||
.unwrap_or_else(One::one),
|
||||
.unwrap_or_else(|| PyInt::new(BigInt::one()).into_ref(vm)),
|
||||
}
|
||||
.into_ref_with_type(vm, cls)
|
||||
}
|
||||
|
||||
fn start(self, _vm: &VirtualMachine) -> PyIntRef {
|
||||
self.start.clone()
|
||||
}
|
||||
|
||||
fn stop(self, _vm: &VirtualMachine) -> PyIntRef {
|
||||
self.stop.clone()
|
||||
}
|
||||
|
||||
fn step(self, _vm: &VirtualMachine) -> PyIntRef {
|
||||
self.step.clone()
|
||||
}
|
||||
|
||||
fn iter(self: PyRangeRef, _vm: &VirtualMachine) -> PyIteratorValue {
|
||||
PyIteratorValue {
|
||||
position: Cell::new(0),
|
||||
iterated_obj: self.into_object(),
|
||||
}
|
||||
}
|
||||
|
||||
fn reversed(self: PyRangeRef, vm: &VirtualMachine) -> PyIteratorValue {
|
||||
let start = self.start.as_bigint();
|
||||
let stop = self.stop.as_bigint();
|
||||
let step = self.step.as_bigint();
|
||||
|
||||
// compute the last element that is actually contained within the range
|
||||
// this is the new start
|
||||
let remainder = ((stop - start) % step).abs();
|
||||
let new_start = if remainder.is_zero() {
|
||||
stop - step
|
||||
} else {
|
||||
stop - &remainder
|
||||
};
|
||||
|
||||
let new_stop: BigInt = match step.sign() {
|
||||
Sign::Plus => start - 1,
|
||||
Sign::Minus => start + 1,
|
||||
Sign::NoSign => unreachable!(),
|
||||
};
|
||||
|
||||
let reversed = PyRange {
|
||||
start: PyInt::new(new_start).into_ref(vm),
|
||||
stop: PyInt::new(new_stop).into_ref(vm),
|
||||
step: PyInt::new(-step).into_ref(vm),
|
||||
};
|
||||
|
||||
PyIteratorValue {
|
||||
position: Cell::new(0),
|
||||
iterated_obj: reversed.into_ref(vm).into_object(),
|
||||
}
|
||||
}
|
||||
|
||||
fn len(self, _vm: &VirtualMachine) -> PyInt {
|
||||
let start = self.start.as_bigint();
|
||||
let stop = self.stop.as_bigint();
|
||||
let step = self.step.as_bigint();
|
||||
|
||||
match step.sign() {
|
||||
Sign::Plus if start < stop => PyInt::new((stop - start - 1usize) / step + 1),
|
||||
Sign::Minus if start > stop => PyInt::new((start - stop - 1usize) / (-step) + 1),
|
||||
Sign::Plus | Sign::Minus => PyInt::new(0),
|
||||
Sign::NoSign => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn repr(self, _vm: &VirtualMachine) -> String {
|
||||
if self.step.as_bigint().is_one() {
|
||||
format!("range({}, {})", self.start, self.stop)
|
||||
} else {
|
||||
format!("range({}, {}, {})", self.start, self.stop, self.step)
|
||||
}
|
||||
}
|
||||
|
||||
fn bool(self, _vm: &VirtualMachine) -> bool {
|
||||
!self.is_empty()
|
||||
}
|
||||
|
||||
fn contains(self, needle: PyObjectRef, _vm: &VirtualMachine) -> bool {
|
||||
if let Ok(int) = needle.downcast::<PyInt>() {
|
||||
match self.offset(int.as_bigint()) {
|
||||
Some(ref offset) => offset.is_multiple_of(self.step.as_bigint()),
|
||||
None => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn index(self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyInt> {
|
||||
if let Ok(int) = needle.downcast::<PyInt>() {
|
||||
match self.index_of(int.as_bigint()) {
|
||||
Some(idx) => Ok(PyInt::new(idx)),
|
||||
None => Err(vm.new_value_error(format!("{} is not in range", int))),
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_value_error("sequence.index(x): x not in sequence".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
fn count(self, item: PyObjectRef, _vm: &VirtualMachine) -> PyInt {
|
||||
if let Ok(int) = item.downcast::<PyInt>() {
|
||||
if self.index_of(int.as_bigint()).is_some() {
|
||||
PyInt::new(1)
|
||||
} else {
|
||||
PyInt::new(0)
|
||||
}
|
||||
} else {
|
||||
PyInt::new(0)
|
||||
}
|
||||
}
|
||||
|
||||
fn getitem(self, subscript: Either<PyIntRef, PySliceRef>, vm: &VirtualMachine) -> PyResult {
|
||||
match subscript {
|
||||
Either::A(index) => {
|
||||
if let Some(value) = self.get(index.value.clone()) {
|
||||
if let Some(value) = self.get(index.as_bigint()) {
|
||||
Ok(PyInt::new(value).into_ref(vm).into_object())
|
||||
} else {
|
||||
Err(vm.new_index_error("range object index out of range".to_string()))
|
||||
}
|
||||
}
|
||||
Either::B(slice) => {
|
||||
let new_start = if let Some(int) = slice.start.clone() {
|
||||
let new_start = if let Some(int) = slice.start.as_ref() {
|
||||
if let Some(i) = self.get(int) {
|
||||
i
|
||||
PyInt::new(i).into_ref(vm)
|
||||
} else {
|
||||
self.start.clone()
|
||||
}
|
||||
@@ -232,9 +274,9 @@ impl PyRangeRef {
|
||||
self.start.clone()
|
||||
};
|
||||
|
||||
let new_end = if let Some(int) = slice.stop.clone() {
|
||||
let new_end = if let Some(int) = slice.stop.as_ref() {
|
||||
if let Some(i) = self.get(int) {
|
||||
i
|
||||
PyInt::new(i).into_ref(vm)
|
||||
} else {
|
||||
self.stop.clone()
|
||||
}
|
||||
@@ -242,8 +284,8 @@ impl PyRangeRef {
|
||||
self.stop.clone()
|
||||
};
|
||||
|
||||
let new_step = if let Some(int) = slice.step.clone() {
|
||||
int * self.step.clone()
|
||||
let new_step = if let Some(int) = slice.step.as_ref() {
|
||||
PyInt::new(int * self.step.as_bigint()).into_ref(vm)
|
||||
} else {
|
||||
self.step.clone()
|
||||
};
|
||||
@@ -271,115 +313,3 @@ fn range_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
|
||||
Ok(range.into_object())
|
||||
}
|
||||
|
||||
fn range_iter(range: PyRangeRef, _vm: &VirtualMachine) -> PyIteratorValue {
|
||||
PyIteratorValue {
|
||||
position: Cell::new(0),
|
||||
iterated_obj: range.into_object(),
|
||||
}
|
||||
}
|
||||
|
||||
fn range_reversed(zelf: PyRangeRef, vm: &VirtualMachine) -> PyIteratorValue {
|
||||
let range = zelf.reversed();
|
||||
|
||||
PyIteratorValue {
|
||||
position: Cell::new(0),
|
||||
iterated_obj: range.into_ref(vm).into_object(),
|
||||
}
|
||||
}
|
||||
|
||||
fn range_len(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.range_type()))]);
|
||||
|
||||
if let Some(len) = get_value(zelf).try_len() {
|
||||
Ok(vm.ctx.new_int(len))
|
||||
} else {
|
||||
Err(vm.new_overflow_error("Python int too large to convert to Rust usize".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
fn range_repr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.range_type()))]);
|
||||
|
||||
let repr = get_value(zelf).repr();
|
||||
|
||||
Ok(vm.ctx.new_str(repr))
|
||||
}
|
||||
|
||||
fn range_bool(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.range_type()))]);
|
||||
|
||||
let len = get_value(zelf).len();
|
||||
|
||||
Ok(vm.ctx.new_bool(len > 0))
|
||||
}
|
||||
|
||||
fn range_contains(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(
|
||||
vm,
|
||||
args,
|
||||
required = [(zelf, Some(vm.ctx.range_type())), (needle, None)]
|
||||
);
|
||||
|
||||
let range = get_value(zelf);
|
||||
|
||||
let result = if objtype::isinstance(needle, &vm.ctx.int_type()) {
|
||||
range.contains(&objint::get_value(needle))
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
Ok(vm.ctx.new_bool(result))
|
||||
}
|
||||
|
||||
fn range_index(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(
|
||||
vm,
|
||||
args,
|
||||
required = [(zelf, Some(vm.ctx.range_type())), (needle, None)]
|
||||
);
|
||||
|
||||
let range = get_value(zelf);
|
||||
|
||||
if objtype::isinstance(needle, &vm.ctx.int_type()) {
|
||||
let needle = objint::get_value(needle);
|
||||
|
||||
match range.index_of(&needle) {
|
||||
Some(idx) => Ok(vm.ctx.new_int(idx)),
|
||||
None => Err(vm.new_value_error(format!("{} is not in range", needle))),
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_value_error("sequence.index(x): x not in sequence".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
fn range_count(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(
|
||||
vm,
|
||||
args,
|
||||
required = [(zelf, Some(vm.ctx.range_type())), (item, None)]
|
||||
);
|
||||
|
||||
let range = get_value(zelf);
|
||||
|
||||
if objtype::isinstance(item, &vm.ctx.int_type()) {
|
||||
Ok(vm.ctx.new_int(range.count(&objint::get_value(item))))
|
||||
} else {
|
||||
Ok(vm.ctx.new_int(0))
|
||||
}
|
||||
}
|
||||
|
||||
fn range_start(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.range_type()))]);
|
||||
Ok(vm.ctx.new_int(get_value(zelf).start))
|
||||
}
|
||||
|
||||
fn range_stop(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.range_type()))]);
|
||||
Ok(vm.ctx.new_int(get_value(zelf).stop))
|
||||
}
|
||||
|
||||
fn range_step(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.range_type()))]);
|
||||
Ok(vm.ctx.new_int(get_value(zelf).step))
|
||||
}
|
||||
@@ -144,7 +144,7 @@ pub fn get_item(
|
||||
subscript: PyObjectRef,
|
||||
) -> PyResult {
|
||||
if let Some(i) = subscript.payload::<PyInt>() {
|
||||
return match i.value.to_i32() {
|
||||
return match i.as_bigint().to_i32() {
|
||||
Some(value) => {
|
||||
if let Some(pos_index) = elements.to_vec().get_pos(value) {
|
||||
let obj = elements[pos_index].clone();
|
||||
@@ -164,11 +164,13 @@ pub fn get_item(
|
||||
Ok(PyObject::new(
|
||||
PyList::from(elements.to_vec().get_slice_items(vm, &subscript)?),
|
||||
sequence.type_pyref(),
|
||||
None,
|
||||
))
|
||||
} else if sequence.payload::<PyTuple>().is_some() {
|
||||
Ok(PyObject::new(
|
||||
PyTuple::from(elements.to_vec().get_slice_items(vm, &subscript)?),
|
||||
sequence.type_pyref(),
|
||||
None,
|
||||
))
|
||||
} else {
|
||||
panic!("sequence get_item called for non-sequence")
|
||||
|
||||
+163
-131
@@ -9,13 +9,14 @@ use std::hash::{Hash, Hasher};
|
||||
|
||||
use crate::function::{OptionalArg, PyFuncArgs};
|
||||
use crate::pyobject::{
|
||||
PyContext, PyIteratorValue, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
|
||||
PyContext, PyIteratorValue, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
|
||||
};
|
||||
use crate::vm::{ReprGuard, VirtualMachine};
|
||||
|
||||
use super::objbool;
|
||||
use super::objint;
|
||||
use super::objiter;
|
||||
use super::objtype;
|
||||
use super::objtype::PyClassRef;
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -24,6 +25,12 @@ pub struct PySet {
|
||||
}
|
||||
pub type PySetRef = PyRef<PySet>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PyFrozenSet {
|
||||
elements: HashMap<u64, PyObjectRef>,
|
||||
}
|
||||
pub type PyFrozenSetRef = PyRef<PyFrozenSet>;
|
||||
|
||||
impl fmt::Debug for PySet {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// TODO: implement more detailed, non-recursive Debug formatter
|
||||
@@ -31,14 +38,65 @@ impl fmt::Debug for PySet {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PyFrozenSet {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// TODO: implement more detailed, non-recursive Debug formatter
|
||||
f.write_str("frozenset")
|
||||
}
|
||||
}
|
||||
|
||||
impl PyValue for PySet {
|
||||
fn class(vm: &VirtualMachine) -> PyClassRef {
|
||||
vm.ctx.set_type()
|
||||
}
|
||||
}
|
||||
|
||||
impl PyValue for PyFrozenSet {
|
||||
fn class(vm: &VirtualMachine) -> PyClassRef {
|
||||
vm.ctx.frozenset_type()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_elements(obj: &PyObjectRef) -> HashMap<u64, PyObjectRef> {
|
||||
obj.payload::<PySet>().unwrap().elements.borrow().clone()
|
||||
if let Some(set) = obj.payload::<PySet>() {
|
||||
return set.elements.borrow().clone();
|
||||
} else if let Some(frozenset) = obj.payload::<PyFrozenSet>() {
|
||||
return frozenset.elements.clone();
|
||||
}
|
||||
panic!("Not frozenset or set");
|
||||
}
|
||||
|
||||
fn validate_set_or_frozenset(vm: &VirtualMachine, cls: PyClassRef) -> PyResult<()> {
|
||||
if !(objtype::issubclass(&cls, &vm.ctx.set_type())
|
||||
|| objtype::issubclass(&cls, &vm.ctx.frozenset_type()))
|
||||
{
|
||||
return Err(vm.new_type_error(format!("{} is not a subtype of set or frozenset", cls)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_set(
|
||||
vm: &VirtualMachine,
|
||||
elements: HashMap<u64, PyObjectRef>,
|
||||
cls: PyClassRef,
|
||||
) -> PyResult {
|
||||
if objtype::issubclass(&cls, &vm.ctx.set_type()) {
|
||||
Ok(PyObject::new(
|
||||
PySet {
|
||||
elements: RefCell::new(elements),
|
||||
},
|
||||
PySet::class(vm),
|
||||
None,
|
||||
))
|
||||
} else if objtype::issubclass(&cls, &vm.ctx.frozenset_type()) {
|
||||
Ok(PyObject::new(
|
||||
PyFrozenSet { elements: elements },
|
||||
PyFrozenSet::class(vm),
|
||||
None,
|
||||
))
|
||||
} else {
|
||||
Err(vm.new_type_error(format!("{} is not a subtype of set or frozenset", cls)))
|
||||
}
|
||||
}
|
||||
|
||||
fn perform_action_with_hash(
|
||||
@@ -152,11 +210,9 @@ fn set_clear(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
}
|
||||
|
||||
/* Create a new object of sub-type of set */
|
||||
fn set_new(
|
||||
cls: PyClassRef,
|
||||
iterable: OptionalArg<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PySetRef> {
|
||||
fn set_new(cls: PyClassRef, iterable: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult {
|
||||
validate_set_or_frozenset(vm, cls.clone())?;
|
||||
|
||||
let elements: HashMap<u64, PyObjectRef> = match iterable {
|
||||
OptionalArg::Missing => HashMap::new(),
|
||||
OptionalArg::Present(iterable) => {
|
||||
@@ -169,25 +225,22 @@ fn set_new(
|
||||
}
|
||||
};
|
||||
|
||||
PySet {
|
||||
elements: RefCell::new(elements),
|
||||
}
|
||||
.into_ref_with_type(vm, cls)
|
||||
create_set(vm, elements, cls.clone())
|
||||
}
|
||||
|
||||
fn set_len(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
trace!("set.len called with: {:?}", args);
|
||||
arg_check!(vm, args, required = [(s, Some(vm.ctx.set_type()))]);
|
||||
arg_check!(vm, args, required = [(s, None)]);
|
||||
validate_set_or_frozenset(vm, s.type_pyref())?;
|
||||
let elements = get_elements(s);
|
||||
Ok(vm.context().new_int(elements.len()))
|
||||
}
|
||||
|
||||
fn set_copy(obj: PySetRef, _vm: &VirtualMachine) -> PySet {
|
||||
fn set_copy(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
trace!("set.copy called with: {:?}", obj);
|
||||
let elements = obj.elements.borrow().clone();
|
||||
PySet {
|
||||
elements: RefCell::new(elements),
|
||||
}
|
||||
validate_set_or_frozenset(vm, obj.type_pyref())?;
|
||||
let elements = get_elements(&obj).clone();
|
||||
create_set(vm, elements, obj.type_pyref())
|
||||
}
|
||||
|
||||
fn set_repr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
@@ -211,11 +264,8 @@ fn set_repr(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
}
|
||||
|
||||
pub fn set_contains(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(
|
||||
vm,
|
||||
args,
|
||||
required = [(set, Some(vm.ctx.set_type())), (needle, None)]
|
||||
);
|
||||
arg_check!(vm, args, required = [(set, None), (needle, None)]);
|
||||
validate_set_or_frozenset(vm, set.type_pyref())?;
|
||||
for element in get_elements(set).iter() {
|
||||
match vm._eq(needle.clone(), element.1.clone()) {
|
||||
Ok(value) => {
|
||||
@@ -281,14 +331,10 @@ fn set_compare_inner(
|
||||
size_func: &Fn(usize, usize) -> bool,
|
||||
swap: bool,
|
||||
) -> PyResult {
|
||||
arg_check!(
|
||||
vm,
|
||||
args,
|
||||
required = [
|
||||
(zelf, Some(vm.ctx.set_type())),
|
||||
(other, Some(vm.ctx.set_type()))
|
||||
]
|
||||
);
|
||||
arg_check!(vm, args, required = [(zelf, None), (other, None)]);
|
||||
|
||||
validate_set_or_frozenset(vm, zelf.type_pyref())?;
|
||||
validate_set_or_frozenset(vm, other.type_pyref())?;
|
||||
|
||||
let get_zelf = |swap: bool| -> &PyObjectRef {
|
||||
if swap {
|
||||
@@ -323,47 +369,48 @@ fn set_compare_inner(
|
||||
Ok(vm.new_bool(true))
|
||||
}
|
||||
|
||||
fn set_union(zelf: PySetRef, other: PySetRef, _vm: &VirtualMachine) -> PySet {
|
||||
let mut elements = zelf.elements.borrow().clone();
|
||||
elements.extend(other.elements.borrow().clone());
|
||||
fn set_union(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
validate_set_or_frozenset(vm, zelf.type_pyref())?;
|
||||
validate_set_or_frozenset(vm, other.type_pyref())?;
|
||||
|
||||
PySet {
|
||||
elements: RefCell::new(elements),
|
||||
}
|
||||
let mut elements = get_elements(&zelf).clone();
|
||||
elements.extend(get_elements(&other).clone());
|
||||
|
||||
create_set(vm, elements, zelf.type_pyref())
|
||||
}
|
||||
|
||||
fn set_intersection(zelf: PySetRef, other: PySetRef, vm: &VirtualMachine) -> PyResult<PySet> {
|
||||
fn set_intersection(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
set_combine_inner(zelf, other, vm, SetCombineOperation::Intersection)
|
||||
}
|
||||
|
||||
fn set_difference(zelf: PySetRef, other: PySetRef, vm: &VirtualMachine) -> PyResult<PySet> {
|
||||
fn set_difference(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
set_combine_inner(zelf, other, vm, SetCombineOperation::Difference)
|
||||
}
|
||||
|
||||
fn set_symmetric_difference(
|
||||
zelf: PySetRef,
|
||||
other: PySetRef,
|
||||
zelf: PyObjectRef,
|
||||
other: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PySet> {
|
||||
) -> PyResult {
|
||||
validate_set_or_frozenset(vm, zelf.type_pyref())?;
|
||||
validate_set_or_frozenset(vm, other.type_pyref())?;
|
||||
let mut elements = HashMap::new();
|
||||
|
||||
for element in zelf.elements.borrow().iter() {
|
||||
let value = vm.call_method(other.as_object(), "__contains__", vec![element.1.clone()])?;
|
||||
for element in get_elements(&zelf).iter() {
|
||||
let value = vm.call_method(&other, "__contains__", vec![element.1.clone()])?;
|
||||
if !objbool::get_value(&value) {
|
||||
elements.insert(element.0.clone(), element.1.clone());
|
||||
}
|
||||
}
|
||||
|
||||
for element in other.elements.borrow().iter() {
|
||||
let value = vm.call_method(zelf.as_object(), "__contains__", vec![element.1.clone()])?;
|
||||
for element in get_elements(&other).iter() {
|
||||
let value = vm.call_method(&zelf, "__contains__", vec![element.1.clone()])?;
|
||||
if !objbool::get_value(&value) {
|
||||
elements.insert(element.0.clone(), element.1.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(PySet {
|
||||
elements: RefCell::new(elements),
|
||||
})
|
||||
create_set(vm, elements, zelf.type_pyref())
|
||||
}
|
||||
|
||||
enum SetCombineOperation {
|
||||
@@ -372,15 +419,17 @@ enum SetCombineOperation {
|
||||
}
|
||||
|
||||
fn set_combine_inner(
|
||||
zelf: PySetRef,
|
||||
other: PySetRef,
|
||||
zelf: PyObjectRef,
|
||||
other: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
op: SetCombineOperation,
|
||||
) -> PyResult<PySet> {
|
||||
) -> PyResult {
|
||||
validate_set_or_frozenset(vm, zelf.type_pyref())?;
|
||||
validate_set_or_frozenset(vm, other.type_pyref())?;
|
||||
let mut elements = HashMap::new();
|
||||
|
||||
for element in zelf.elements.borrow().iter() {
|
||||
let value = vm.call_method(other.as_object(), "__contains__", vec![element.1.clone()])?;
|
||||
for element in get_elements(&zelf).iter() {
|
||||
let value = vm.call_method(&other, "__contains__", vec![element.1.clone()])?;
|
||||
let should_add = match op {
|
||||
SetCombineOperation::Intersection => objbool::get_value(&value),
|
||||
SetCombineOperation::Difference => !objbool::get_value(&value),
|
||||
@@ -390,9 +439,7 @@ fn set_combine_inner(
|
||||
}
|
||||
}
|
||||
|
||||
Ok(PySet {
|
||||
elements: RefCell::new(elements),
|
||||
})
|
||||
create_set(vm, elements, zelf.type_pyref())
|
||||
}
|
||||
|
||||
fn set_pop(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
@@ -548,65 +595,43 @@ pub fn init(context: &PyContext) {
|
||||
set(iterable) -> new set object\n\n\
|
||||
Build an unordered collection of unique elements.";
|
||||
|
||||
context.set_attr(set_type, "__contains__", context.new_rustfunc(set_contains));
|
||||
context.set_attr(set_type, "__len__", context.new_rustfunc(set_len));
|
||||
context.set_attr(set_type, "__new__", context.new_rustfunc(set_new));
|
||||
context.set_attr(set_type, "__repr__", context.new_rustfunc(set_repr));
|
||||
context.set_attr(set_type, "__eq__", context.new_rustfunc(set_eq));
|
||||
context.set_attr(set_type, "__ge__", context.new_rustfunc(set_ge));
|
||||
context.set_attr(set_type, "__gt__", context.new_rustfunc(set_gt));
|
||||
context.set_attr(set_type, "__le__", context.new_rustfunc(set_le));
|
||||
context.set_attr(set_type, "__lt__", context.new_rustfunc(set_lt));
|
||||
context.set_attr(set_type, "issubset", context.new_rustfunc(set_le));
|
||||
context.set_attr(set_type, "issuperset", context.new_rustfunc(set_ge));
|
||||
context.set_attr(set_type, "union", context.new_rustfunc(set_union));
|
||||
context.set_attr(set_type, "__or__", context.new_rustfunc(set_union));
|
||||
context.set_attr(
|
||||
set_type,
|
||||
"intersection",
|
||||
context.new_rustfunc(set_intersection),
|
||||
);
|
||||
context.set_attr(set_type, "__and__", context.new_rustfunc(set_intersection));
|
||||
context.set_attr(set_type, "difference", context.new_rustfunc(set_difference));
|
||||
context.set_attr(set_type, "__sub__", context.new_rustfunc(set_difference));
|
||||
context.set_attr(
|
||||
set_type,
|
||||
"symmetric_difference",
|
||||
context.new_rustfunc(set_symmetric_difference),
|
||||
);
|
||||
context.set_attr(
|
||||
set_type,
|
||||
"__xor__",
|
||||
context.new_rustfunc(set_symmetric_difference),
|
||||
);
|
||||
context.set_attr(set_type, "__doc__", context.new_str(set_doc.to_string()));
|
||||
context.set_attr(set_type, "add", context.new_rustfunc(set_add));
|
||||
context.set_attr(set_type, "remove", context.new_rustfunc(set_remove));
|
||||
context.set_attr(set_type, "discard", context.new_rustfunc(set_discard));
|
||||
context.set_attr(set_type, "clear", context.new_rustfunc(set_clear));
|
||||
context.set_attr(set_type, "copy", context.new_rustfunc(set_copy));
|
||||
context.set_attr(set_type, "pop", context.new_rustfunc(set_pop));
|
||||
context.set_attr(set_type, "update", context.new_rustfunc(set_update));
|
||||
context.set_attr(set_type, "__ior__", context.new_rustfunc(set_ior));
|
||||
context.set_attr(
|
||||
set_type,
|
||||
"intersection_update",
|
||||
context.new_rustfunc(set_intersection_update),
|
||||
);
|
||||
context.set_attr(set_type, "__iand__", context.new_rustfunc(set_iand));
|
||||
context.set_attr(
|
||||
set_type,
|
||||
"difference_update",
|
||||
context.new_rustfunc(set_difference_update),
|
||||
);
|
||||
context.set_attr(set_type, "__isub__", context.new_rustfunc(set_isub));
|
||||
context.set_attr(
|
||||
set_type,
|
||||
"symmetric_difference_update",
|
||||
context.new_rustfunc(set_symmetric_difference_update),
|
||||
);
|
||||
context.set_attr(set_type, "__ixor__", context.new_rustfunc(set_ixor));
|
||||
context.set_attr(set_type, "__iter__", context.new_rustfunc(set_iter));
|
||||
extend_class!(context, set_type, {
|
||||
"__contains__" => context.new_rustfunc(set_contains),
|
||||
"__len__" => context.new_rustfunc(set_len),
|
||||
"__new__" => context.new_rustfunc(set_new),
|
||||
"__repr__" => context.new_rustfunc(set_repr),
|
||||
"__eq__" => context.new_rustfunc(set_eq),
|
||||
"__ge__" => context.new_rustfunc(set_ge),
|
||||
"__gt__" => context.new_rustfunc(set_gt),
|
||||
"__le__" => context.new_rustfunc(set_le),
|
||||
"__lt__" => context.new_rustfunc(set_lt),
|
||||
"issubset" => context.new_rustfunc(set_le),
|
||||
"issuperset" => context.new_rustfunc(set_ge),
|
||||
"union" => context.new_rustfunc(set_union),
|
||||
"__or__" => context.new_rustfunc(set_union),
|
||||
"intersection" => context.new_rustfunc(set_intersection),
|
||||
"__and__" => context.new_rustfunc(set_intersection),
|
||||
"difference" => context.new_rustfunc(set_difference),
|
||||
"__sub__" => context.new_rustfunc(set_difference),
|
||||
"symmetric_difference" => context.new_rustfunc(set_symmetric_difference),
|
||||
"__xor__" => context.new_rustfunc(set_symmetric_difference),
|
||||
"__doc__" => context.new_str(set_doc.to_string()),
|
||||
"add" => context.new_rustfunc(set_add),
|
||||
"remove" => context.new_rustfunc(set_remove),
|
||||
"discard" => context.new_rustfunc(set_discard),
|
||||
"clear" => context.new_rustfunc(set_clear),
|
||||
"copy" => context.new_rustfunc(set_copy),
|
||||
"pop" => context.new_rustfunc(set_pop),
|
||||
"update" => context.new_rustfunc(set_update),
|
||||
"__ior__" => context.new_rustfunc(set_ior),
|
||||
"intersection_update" => context.new_rustfunc(set_intersection_update),
|
||||
"__iand__" => context.new_rustfunc(set_iand),
|
||||
"difference_update" => context.new_rustfunc(set_difference_update),
|
||||
"__isub__" => context.new_rustfunc(set_isub),
|
||||
"symmetric_difference_update" => context.new_rustfunc(set_symmetric_difference_update),
|
||||
"__ixor__" => context.new_rustfunc(set_ixor),
|
||||
"__iter__" => context.new_rustfunc(set_iter)
|
||||
});
|
||||
|
||||
let frozenset_type = &context.frozenset_type;
|
||||
|
||||
@@ -614,20 +639,27 @@ pub fn init(context: &PyContext) {
|
||||
frozenset(iterable) -> frozenset object\n\n\
|
||||
Build an immutable unordered collection of unique elements.";
|
||||
|
||||
context.set_attr(
|
||||
frozenset_type,
|
||||
"__contains__",
|
||||
context.new_rustfunc(set_contains),
|
||||
);
|
||||
context.set_attr(frozenset_type, "__len__", context.new_rustfunc(set_len));
|
||||
context.set_attr(
|
||||
frozenset_type,
|
||||
"__doc__",
|
||||
context.new_str(frozenset_doc.to_string()),
|
||||
);
|
||||
context.set_attr(
|
||||
frozenset_type,
|
||||
"__repr__",
|
||||
context.new_rustfunc(frozenset_repr),
|
||||
);
|
||||
extend_class!(context, frozenset_type, {
|
||||
"__new__" => context.new_rustfunc(set_new),
|
||||
"__eq__" => context.new_rustfunc(set_eq),
|
||||
"__ge__" => context.new_rustfunc(set_ge),
|
||||
"__gt__" => context.new_rustfunc(set_gt),
|
||||
"__le__" => context.new_rustfunc(set_le),
|
||||
"__lt__" => context.new_rustfunc(set_lt),
|
||||
"issubset" => context.new_rustfunc(set_le),
|
||||
"issuperset" => context.new_rustfunc(set_ge),
|
||||
"union" => context.new_rustfunc(set_union),
|
||||
"__or__" => context.new_rustfunc(set_union),
|
||||
"intersection" => context.new_rustfunc(set_intersection),
|
||||
"__and__" => context.new_rustfunc(set_intersection),
|
||||
"difference" => context.new_rustfunc(set_difference),
|
||||
"__sub__" => context.new_rustfunc(set_difference),
|
||||
"symmetric_difference" => context.new_rustfunc(set_symmetric_difference),
|
||||
"__xor__" => context.new_rustfunc(set_symmetric_difference),
|
||||
"__contains__" => context.new_rustfunc(set_contains),
|
||||
"__len__" => context.new_rustfunc(set_len),
|
||||
"__doc__" => context.new_str(frozenset_doc.to_string()),
|
||||
"__repr__" => context.new_rustfunc(frozenset_repr),
|
||||
"copy" => context.new_rustfunc(set_copy)
|
||||
});
|
||||
}
|
||||
+35
-34
@@ -22,6 +22,7 @@ pub struct PyClass {
|
||||
pub name: String,
|
||||
pub mro: Vec<PyClassRef>,
|
||||
pub subclasses: RefCell<Vec<PyWeak>>,
|
||||
pub attributes: RefCell<PyAttributes>,
|
||||
}
|
||||
|
||||
impl fmt::Display for PyClass {
|
||||
@@ -109,8 +110,8 @@ impl PyClassRef {
|
||||
format!("<class '{}'>", self.name)
|
||||
}
|
||||
|
||||
fn prepare(_name: PyStringRef, _bases: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
vm.new_dict()
|
||||
fn prepare(_name: PyStringRef, _bases: PyObjectRef, vm: &VirtualMachine) -> PyDictRef {
|
||||
vm.ctx.new_dict()
|
||||
}
|
||||
|
||||
fn getattribute(self, name_ref: PyStringRef, vm: &VirtualMachine) -> PyResult {
|
||||
@@ -149,6 +150,25 @@ impl PyClassRef {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_attr(
|
||||
self,
|
||||
attr_name: PyStringRef,
|
||||
value: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
if let Some(attr) = class_get_attr(&self.type_pyref(), &attr_name.value) {
|
||||
if let Some(descriptor) = class_get_attr(&attr.type_pyref(), "__set__") {
|
||||
vm.invoke(descriptor, vec![attr, self.into_object(), value])?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
self.attributes
|
||||
.borrow_mut()
|
||||
.insert(attr_name.to_string(), value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn subclasses(self, _vm: &VirtualMachine) -> PyList {
|
||||
let mut subclasses = self.subclasses.borrow_mut();
|
||||
subclasses.retain(|x| x.upgrade().is_some());
|
||||
@@ -181,6 +201,7 @@ pub fn init(ctx: &PyContext) {
|
||||
"__repr__" => ctx.new_rustfunc(PyClassRef::repr),
|
||||
"__prepare__" => ctx.new_rustfunc(PyClassRef::prepare),
|
||||
"__getattribute__" => ctx.new_rustfunc(PyClassRef::getattribute),
|
||||
"__setattr__" => ctx.new_rustfunc(PyClassRef::set_attr),
|
||||
"__subclasses__" => ctx.new_rustfunc(PyClassRef::subclasses),
|
||||
"__getattribute__" => ctx.new_rustfunc(PyClassRef::getattribute),
|
||||
"__instancecheck__" => ctx.new_rustfunc(PyClassRef::instance_check),
|
||||
@@ -260,32 +281,13 @@ pub fn type_call(class: PyClassRef, args: Args, kwargs: KwArgs, vm: &VirtualMach
|
||||
Ok(obj)
|
||||
}
|
||||
|
||||
// Very private helper function for class_get_attr
|
||||
fn class_get_attr_in_dict(class: &PyClassRef, attr_name: &str) -> Option<PyObjectRef> {
|
||||
if let Some(ref dict) = class.as_object().dict {
|
||||
dict.borrow().get(attr_name).cloned()
|
||||
} else {
|
||||
panic!("Only classes should be in MRO!");
|
||||
}
|
||||
}
|
||||
|
||||
// Very private helper function for class_has_attr
|
||||
fn class_has_attr_in_dict(class: &PyClassRef, attr_name: &str) -> bool {
|
||||
if let Some(ref dict) = class.as_object().dict {
|
||||
dict.borrow().contains_key(attr_name)
|
||||
} else {
|
||||
panic!("All classes are expected to have dicts!");
|
||||
}
|
||||
}
|
||||
|
||||
// This is the internal get_attr implementation for fast lookup on a class.
|
||||
pub fn class_get_attr(zelf: &PyClassRef, attr_name: &str) -> Option<PyObjectRef> {
|
||||
let mro = &zelf.mro;
|
||||
if let Some(item) = class_get_attr_in_dict(zelf, attr_name) {
|
||||
pub fn class_get_attr(class: &PyClassRef, attr_name: &str) -> Option<PyObjectRef> {
|
||||
if let Some(item) = class.attributes.borrow().get(attr_name).cloned() {
|
||||
return Some(item);
|
||||
}
|
||||
for class in mro {
|
||||
if let Some(item) = class_get_attr_in_dict(class, attr_name) {
|
||||
for class in &class.mro {
|
||||
if let Some(item) = class.attributes.borrow().get(attr_name).cloned() {
|
||||
return Some(item);
|
||||
}
|
||||
}
|
||||
@@ -293,12 +295,12 @@ pub fn class_get_attr(zelf: &PyClassRef, attr_name: &str) -> Option<PyObjectRef>
|
||||
}
|
||||
|
||||
// This is the internal has_attr implementation for fast lookup on a class.
|
||||
pub fn class_has_attr(zelf: &PyClassRef, attr_name: &str) -> bool {
|
||||
class_has_attr_in_dict(zelf, attr_name)
|
||||
|| zelf
|
||||
pub fn class_has_attr(class: &PyClassRef, attr_name: &str) -> bool {
|
||||
class.attributes.borrow().contains_key(attr_name)
|
||||
|| class
|
||||
.mro
|
||||
.iter()
|
||||
.any(|d| class_has_attr_in_dict(d, attr_name))
|
||||
.any(|c| c.attributes.borrow().contains_key(attr_name))
|
||||
}
|
||||
|
||||
pub fn get_attributes(cls: PyClassRef) -> PyAttributes {
|
||||
@@ -309,10 +311,8 @@ pub fn get_attributes(cls: PyClassRef) -> PyAttributes {
|
||||
base_classes.reverse();
|
||||
|
||||
for bc in base_classes {
|
||||
if let Some(ref dict) = &bc.as_object().dict {
|
||||
for (name, value) in dict.borrow().iter() {
|
||||
attributes.insert(name.to_string(), value.clone());
|
||||
}
|
||||
for (name, value) in bc.attributes.borrow().iter() {
|
||||
attributes.insert(name.to_string(), value.clone());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,8 +374,9 @@ pub fn new(
|
||||
name: String::from(name),
|
||||
mro,
|
||||
subclasses: RefCell::new(vec![]),
|
||||
attributes: RefCell::new(dict),
|
||||
},
|
||||
dict: Some(RefCell::new(dict)),
|
||||
dict: None,
|
||||
typ,
|
||||
}
|
||||
.into_ref();
|
||||
|
||||
+52
-52
@@ -24,7 +24,7 @@ use crate::obj::objclassmethod;
|
||||
use crate::obj::objcode;
|
||||
use crate::obj::objcode::PyCodeRef;
|
||||
use crate::obj::objcomplex::{self, PyComplex};
|
||||
use crate::obj::objdict::{self, PyDict};
|
||||
use crate::obj::objdict::{self, PyDict, PyDictRef};
|
||||
use crate::obj::objellipsis;
|
||||
use crate::obj::objenumerate;
|
||||
use crate::obj::objfilter;
|
||||
@@ -186,22 +186,24 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
|
||||
let (type_type, object_type) = unsafe {
|
||||
let object_type = PyObject {
|
||||
typ: mem::uninitialized(), // !
|
||||
dict: Some(RefCell::new(PyAttributes::new())),
|
||||
dict: None,
|
||||
payload: PyClass {
|
||||
name: String::from("object"),
|
||||
mro: vec![],
|
||||
subclasses: RefCell::new(vec![]),
|
||||
attributes: RefCell::new(PyAttributes::new()),
|
||||
},
|
||||
}
|
||||
.into_ref();
|
||||
|
||||
let type_type = PyObject {
|
||||
typ: mem::uninitialized(), // !
|
||||
dict: Some(RefCell::new(PyAttributes::new())),
|
||||
dict: None,
|
||||
payload: PyClass {
|
||||
name: String::from("type"),
|
||||
mro: vec![object_type.clone().downcast().unwrap()],
|
||||
subclasses: RefCell::new(vec![]),
|
||||
attributes: RefCell::new(PyAttributes::new()),
|
||||
},
|
||||
}
|
||||
.into_ref();
|
||||
@@ -269,7 +271,7 @@ impl PyContext {
|
||||
|
||||
fn create_object<T: PyObjectPayload>(payload: T, cls: &PyClassRef) -> PyRef<T> {
|
||||
PyRef {
|
||||
obj: PyObject::new(payload, cls.clone()),
|
||||
obj: PyObject::new(payload, cls.clone(), None),
|
||||
_payload: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -519,32 +521,32 @@ impl PyContext {
|
||||
self.object.clone()
|
||||
}
|
||||
|
||||
pub fn new_object(&self) -> PyObjectRef {
|
||||
self.new_instance(self.object.clone(), None)
|
||||
}
|
||||
|
||||
pub fn new_int<T: Into<BigInt>>(&self, i: T) -> PyObjectRef {
|
||||
PyObject::new(PyInt::new(i), self.int_type())
|
||||
PyObject::new(PyInt::new(i), self.int_type(), None)
|
||||
}
|
||||
|
||||
pub fn new_float(&self, value: f64) -> PyObjectRef {
|
||||
PyObject::new(PyFloat::from(value), self.float_type())
|
||||
PyObject::new(PyFloat::from(value), self.float_type(), None)
|
||||
}
|
||||
|
||||
pub fn new_complex(&self, value: Complex64) -> PyObjectRef {
|
||||
PyObject::new(PyComplex::from(value), self.complex_type())
|
||||
PyObject::new(PyComplex::from(value), self.complex_type(), None)
|
||||
}
|
||||
|
||||
pub fn new_str(&self, s: String) -> PyObjectRef {
|
||||
PyObject::new(objstr::PyString { value: s }, self.str_type())
|
||||
PyObject::new(objstr::PyString { value: s }, self.str_type(), None)
|
||||
}
|
||||
|
||||
pub fn new_bytes(&self, data: Vec<u8>) -> PyObjectRef {
|
||||
PyObject::new(objbytes::PyBytes::new(data), self.bytes_type())
|
||||
PyObject::new(objbytes::PyBytes::new(data), self.bytes_type(), None)
|
||||
}
|
||||
|
||||
pub fn new_bytearray(&self, data: Vec<u8>) -> PyObjectRef {
|
||||
PyObject::new(objbytearray::PyByteArray::new(data), self.bytearray_type())
|
||||
PyObject::new(
|
||||
objbytearray::PyByteArray::new(data),
|
||||
self.bytearray_type(),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_bool(&self, b: bool) -> PyObjectRef {
|
||||
@@ -556,21 +558,23 @@ impl PyContext {
|
||||
}
|
||||
|
||||
pub fn new_tuple(&self, elements: Vec<PyObjectRef>) -> PyObjectRef {
|
||||
PyObject::new(PyTuple::from(elements), self.tuple_type())
|
||||
PyObject::new(PyTuple::from(elements), self.tuple_type(), None)
|
||||
}
|
||||
|
||||
pub fn new_list(&self, elements: Vec<PyObjectRef>) -> PyObjectRef {
|
||||
PyObject::new(PyList::from(elements), self.list_type())
|
||||
PyObject::new(PyList::from(elements), self.list_type(), None)
|
||||
}
|
||||
|
||||
pub fn new_set(&self) -> PyObjectRef {
|
||||
// Initialized empty, as calling __hash__ is required for adding each object to the set
|
||||
// which requires a VM context - this is done in the objset code itself.
|
||||
PyObject::new(PySet::default(), self.set_type())
|
||||
PyObject::new(PySet::default(), self.set_type(), None)
|
||||
}
|
||||
|
||||
pub fn new_dict(&self) -> PyObjectRef {
|
||||
PyObject::new(PyDict::default(), self.dict_type())
|
||||
pub fn new_dict(&self) -> PyDictRef {
|
||||
PyObject::new(PyDict::default(), self.dict_type(), None)
|
||||
.downcast()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn new_class(&self, name: &str, base: PyClassRef) -> PyClassRef {
|
||||
@@ -578,16 +582,16 @@ impl PyContext {
|
||||
}
|
||||
|
||||
pub fn new_scope(&self) -> Scope {
|
||||
Scope::new(None, self.new_dict())
|
||||
Scope::new(None, self.new_dict().into_object())
|
||||
}
|
||||
|
||||
pub fn new_module(&self, name: &str, dict: PyObjectRef) -> PyObjectRef {
|
||||
pub fn new_module(&self, name: &str, dict: PyDictRef) -> PyObjectRef {
|
||||
PyObject::new(
|
||||
PyModule {
|
||||
name: name.to_string(),
|
||||
dict,
|
||||
},
|
||||
self.module_type.clone(),
|
||||
Some(dict),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -598,6 +602,7 @@ impl PyContext {
|
||||
PyObject::new(
|
||||
PyBuiltinFunction::new(f.into_func()),
|
||||
self.builtin_function_or_method_type(),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -609,7 +614,7 @@ impl PyContext {
|
||||
}
|
||||
|
||||
pub fn new_code_object(&self, code: bytecode::CodeObject) -> PyObjectRef {
|
||||
PyObject::new(objcode::PyCode::new(code), self.code_type())
|
||||
PyObject::new(objcode::PyCode::new(code), self.code_type(), None)
|
||||
}
|
||||
|
||||
pub fn new_function(
|
||||
@@ -621,18 +626,22 @@ impl PyContext {
|
||||
PyObject::new(
|
||||
PyFunction::new(code_obj, scope, defaults),
|
||||
self.function_type(),
|
||||
Some(self.new_dict()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_bound_method(&self, function: PyObjectRef, object: PyObjectRef) -> PyObjectRef {
|
||||
PyObject::new(PyMethod::new(object, function), self.bound_method_type())
|
||||
PyObject::new(
|
||||
PyMethod::new(object, function),
|
||||
self.bound_method_type(),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_instance(&self, class: PyClassRef, dict: Option<PyAttributes>) -> PyObjectRef {
|
||||
let dict = dict.unwrap_or_default();
|
||||
pub fn new_instance(&self, class: PyClassRef, dict: Option<PyDictRef>) -> PyObjectRef {
|
||||
PyObject {
|
||||
typ: class,
|
||||
dict: Some(RefCell::new(dict)),
|
||||
dict: dict,
|
||||
payload: objobject::PyInstance,
|
||||
}
|
||||
.into_ref()
|
||||
@@ -655,11 +664,12 @@ impl PyContext {
|
||||
value: V,
|
||||
) {
|
||||
let obj = obj.into();
|
||||
if let Some(PyModule { ref dict, .. }) = obj.payload::<PyModule>() {
|
||||
dict.set_item(self, attr_name, value.into())
|
||||
} else if let Some(ref dict) = obj.dict {
|
||||
dict.borrow_mut()
|
||||
if let Some(PyClass { ref attributes, .. }) = obj.payload::<PyClass>() {
|
||||
attributes
|
||||
.borrow_mut()
|
||||
.insert(attr_name.to_string(), value.into());
|
||||
} else if let Some(ref dict) = obj.dict {
|
||||
dict.set_item(self, attr_name, value.into());
|
||||
} else {
|
||||
unimplemented!("set_attr unimplemented for: {:?}", obj);
|
||||
};
|
||||
@@ -701,7 +711,7 @@ where
|
||||
T: ?Sized + PyObjectPayload,
|
||||
{
|
||||
pub typ: PyClassRef,
|
||||
pub dict: Option<RefCell<PyAttributes>>, // __dict__ member
|
||||
pub dict: Option<PyDictRef>, // __dict__ member
|
||||
pub payload: T,
|
||||
}
|
||||
|
||||
@@ -911,8 +921,6 @@ impl DictProtocol for PyObjectRef {
|
||||
fn get_item(&self, k: &str) -> Option<PyObjectRef> {
|
||||
if let Some(dict) = self.payload::<PyDict>() {
|
||||
objdict::content_get_key_str(&dict.entries.borrow(), k)
|
||||
} else if let Some(PyModule { ref dict, .. }) = self.payload::<PyModule>() {
|
||||
dict.get_item(k)
|
||||
} else {
|
||||
panic!("TODO {:?}", k)
|
||||
}
|
||||
@@ -921,8 +929,6 @@ impl DictProtocol for PyObjectRef {
|
||||
fn get_key_value_pairs(&self) -> Vec<(PyObjectRef, PyObjectRef)> {
|
||||
if self.payload_is::<PyDict>() {
|
||||
objdict::get_key_value_pairs(self)
|
||||
} else if let Some(PyModule { ref dict, .. }) = self.payload::<PyModule>() {
|
||||
dict.get_key_value_pairs()
|
||||
} else {
|
||||
panic!("TODO")
|
||||
}
|
||||
@@ -933,8 +939,6 @@ impl DictProtocol for PyObjectRef {
|
||||
if let Some(dict) = self.payload::<PyDict>() {
|
||||
let key = ctx.new_str(key.to_string());
|
||||
objdict::set_item_in_content(&mut dict.entries.borrow_mut(), &key, &v);
|
||||
} else if let Some(PyModule { ref dict, .. }) = self.payload::<PyModule>() {
|
||||
dict.set_item(ctx, key, v);
|
||||
} else {
|
||||
panic!("TODO {:?}", self);
|
||||
}
|
||||
@@ -1115,7 +1119,7 @@ where
|
||||
T: PyValue + Sized,
|
||||
{
|
||||
fn into_pyobject(self, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(PyObject::new(self, T::class(vm)))
|
||||
Ok(PyObject::new(self, T::class(vm), None))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1137,19 +1141,10 @@ impl<T> PyObject<T>
|
||||
where
|
||||
T: Sized + PyObjectPayload,
|
||||
{
|
||||
pub fn new(payload: T, typ: PyClassRef) -> PyObjectRef {
|
||||
pub fn new(payload: T, typ: PyClassRef, dict: Option<PyDictRef>) -> PyObjectRef {
|
||||
PyObject {
|
||||
typ,
|
||||
dict: Some(RefCell::new(PyAttributes::new())),
|
||||
payload,
|
||||
}
|
||||
.into_ref()
|
||||
}
|
||||
|
||||
pub fn new_without_dict(payload: T, typ: PyClassRef) -> PyObjectRef {
|
||||
PyObject {
|
||||
typ,
|
||||
dict: None,
|
||||
dict: dict,
|
||||
payload,
|
||||
}
|
||||
.into_ref()
|
||||
@@ -1178,7 +1173,7 @@ pub trait PyValue: fmt::Debug + Sized + 'static {
|
||||
|
||||
fn into_ref(self, vm: &VirtualMachine) -> PyRef<Self> {
|
||||
PyRef {
|
||||
obj: PyObject::new(self, Self::class(vm)),
|
||||
obj: PyObject::new(self, Self::class(vm), None),
|
||||
_payload: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -1186,8 +1181,13 @@ pub trait PyValue: fmt::Debug + Sized + 'static {
|
||||
fn into_ref_with_type(self, vm: &VirtualMachine, cls: PyClassRef) -> PyResult<PyRef<Self>> {
|
||||
let class = Self::class(vm);
|
||||
if objtype::issubclass(&cls, &class) {
|
||||
let dict = if cls.is(&class) {
|
||||
None
|
||||
} else {
|
||||
Some(vm.ctx.new_dict())
|
||||
};
|
||||
Ok(PyRef {
|
||||
obj: PyObject::new(self, cls),
|
||||
obj: PyObject::new(self, cls, dict),
|
||||
_payload: PhantomData,
|
||||
})
|
||||
} else {
|
||||
|
||||
+238
-221
@@ -11,9 +11,20 @@ use rustpython_parser::{ast, parser};
|
||||
|
||||
use crate::function::PyFuncArgs;
|
||||
use crate::obj::objstr;
|
||||
use crate::pyobject::{PyContext, PyObjectRef, PyResult, TypeProtocol};
|
||||
use crate::obj::objtype::PyClassRef;
|
||||
use crate::pyobject::{PyContext, PyObject, PyObjectRef, PyResult, PyValue, TypeProtocol};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AstNode;
|
||||
// type AstNodeRef = PyRef<AstNode>;
|
||||
|
||||
impl PyValue for AstNode {
|
||||
fn class(vm: &VirtualMachine) -> PyClassRef {
|
||||
vm.class("ast", "AST")
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Idea: maybe we can create a sort of struct with some helper functions?
|
||||
struct AstToPyAst {
|
||||
@@ -30,35 +41,35 @@ impl AstToPyAst {
|
||||
}
|
||||
*/
|
||||
|
||||
fn program_to_ast(ctx: &PyContext, program: &ast::Program) -> PyObjectRef {
|
||||
fn program_to_ast(vm: &VirtualMachine, program: &ast::Program) -> PyObjectRef {
|
||||
let mut body = vec![];
|
||||
for statement in &program.statements {
|
||||
body.push(statement_to_ast(ctx, statement));
|
||||
body.push(statement_to_ast(&vm, statement));
|
||||
}
|
||||
// TODO: create Module node:
|
||||
// let ast_node = ctx.new_instance(this.Module);
|
||||
let ast_node = ctx.new_object();
|
||||
let py_body = ctx.new_list(body);
|
||||
ctx.set_attr(&ast_node, "body", py_body);
|
||||
let ast_node = create_node(vm, "program");
|
||||
let py_body = vm.ctx.new_list(body);
|
||||
vm.ctx.set_attr(&ast_node, "body", py_body);
|
||||
ast_node
|
||||
}
|
||||
|
||||
// Create a node class instance
|
||||
fn create_node(ctx: &PyContext, _name: &str) -> PyObjectRef {
|
||||
fn create_node(vm: &VirtualMachine, _name: &str) -> PyObjectRef {
|
||||
// TODO: instantiate a class of type given by name
|
||||
// TODO: lookup in the current module?
|
||||
ctx.new_object()
|
||||
PyObject::new(AstNode, AstNode::class(vm), Some(vm.ctx.new_dict()))
|
||||
}
|
||||
|
||||
fn statements_to_ast(ctx: &PyContext, statements: &[ast::LocatedStatement]) -> PyObjectRef {
|
||||
fn statements_to_ast(vm: &VirtualMachine, statements: &[ast::LocatedStatement]) -> PyObjectRef {
|
||||
let mut py_statements = vec![];
|
||||
for statement in statements {
|
||||
py_statements.push(statement_to_ast(ctx, statement));
|
||||
py_statements.push(statement_to_ast(vm, statement));
|
||||
}
|
||||
ctx.new_list(py_statements)
|
||||
vm.ctx.new_list(py_statements)
|
||||
}
|
||||
|
||||
fn statement_to_ast(ctx: &PyContext, statement: &ast::LocatedStatement) -> PyObjectRef {
|
||||
fn statement_to_ast(vm: &VirtualMachine, statement: &ast::LocatedStatement) -> PyObjectRef {
|
||||
let node = match &statement.node {
|
||||
ast::Statement::ClassDef {
|
||||
name,
|
||||
@@ -66,17 +77,18 @@ fn statement_to_ast(ctx: &PyContext, statement: &ast::LocatedStatement) -> PyObj
|
||||
decorator_list,
|
||||
..
|
||||
} => {
|
||||
let node = create_node(ctx, "ClassDef");
|
||||
let node = create_node(vm, "ClassDef");
|
||||
|
||||
// Set name:
|
||||
ctx.set_attr(&node, "name", ctx.new_str(name.to_string()));
|
||||
vm.ctx
|
||||
.set_attr(&node, "name", vm.ctx.new_str(name.to_string()));
|
||||
|
||||
// Set body:
|
||||
let py_body = statements_to_ast(ctx, body);
|
||||
ctx.set_attr(&node, "body", py_body);
|
||||
let py_body = statements_to_ast(vm, body);
|
||||
vm.ctx.set_attr(&node, "body", py_body);
|
||||
|
||||
let py_decorator_list = expressions_to_ast(ctx, decorator_list);
|
||||
ctx.set_attr(&node, "decorator_list", py_decorator_list);
|
||||
let py_decorator_list = expressions_to_ast(vm, decorator_list);
|
||||
vm.ctx.set_attr(&node, "decorator_list", py_decorator_list);
|
||||
node
|
||||
}
|
||||
ast::Statement::FunctionDef {
|
||||
@@ -86,80 +98,83 @@ fn statement_to_ast(ctx: &PyContext, statement: &ast::LocatedStatement) -> PyObj
|
||||
decorator_list,
|
||||
returns,
|
||||
} => {
|
||||
let node = create_node(ctx, "FunctionDef");
|
||||
let node = create_node(vm, "FunctionDef");
|
||||
|
||||
// Set name:
|
||||
ctx.set_attr(&node, "name", ctx.new_str(name.to_string()));
|
||||
vm.ctx
|
||||
.set_attr(&node, "name", vm.ctx.new_str(name.to_string()));
|
||||
|
||||
ctx.set_attr(&node, "args", parameters_to_ast(ctx, args));
|
||||
vm.ctx.set_attr(&node, "args", parameters_to_ast(vm, args));
|
||||
|
||||
// Set body:
|
||||
let py_body = statements_to_ast(ctx, body);
|
||||
ctx.set_attr(&node, "body", py_body);
|
||||
let py_body = statements_to_ast(vm, body);
|
||||
vm.ctx.set_attr(&node, "body", py_body);
|
||||
|
||||
let py_decorator_list = expressions_to_ast(ctx, decorator_list);
|
||||
ctx.set_attr(&node, "decorator_list", py_decorator_list);
|
||||
let py_decorator_list = expressions_to_ast(vm, decorator_list);
|
||||
vm.ctx.set_attr(&node, "decorator_list", py_decorator_list);
|
||||
|
||||
let py_returns = if let Some(hint) = returns {
|
||||
expression_to_ast(ctx, hint)
|
||||
expression_to_ast(vm, hint)
|
||||
} else {
|
||||
ctx.none()
|
||||
vm.ctx.none()
|
||||
};
|
||||
ctx.set_attr(&node, "returns", py_returns);
|
||||
vm.ctx.set_attr(&node, "returns", py_returns);
|
||||
node
|
||||
}
|
||||
ast::Statement::Continue => create_node(ctx, "Continue"),
|
||||
ast::Statement::Break => create_node(ctx, "Break"),
|
||||
ast::Statement::Pass => create_node(ctx, "Pass"),
|
||||
ast::Statement::Continue => create_node(vm, "Continue"),
|
||||
ast::Statement::Break => create_node(vm, "Break"),
|
||||
ast::Statement::Pass => create_node(vm, "Pass"),
|
||||
ast::Statement::Assert { test, msg } => {
|
||||
let node = create_node(ctx, "Pass");
|
||||
let node = create_node(vm, "Pass");
|
||||
|
||||
ctx.set_attr(&node, "test", expression_to_ast(ctx, test));
|
||||
vm.ctx.set_attr(&node, "test", expression_to_ast(vm, test));
|
||||
|
||||
let py_msg = match msg {
|
||||
Some(msg) => expression_to_ast(ctx, msg),
|
||||
None => ctx.none(),
|
||||
Some(msg) => expression_to_ast(vm, msg),
|
||||
None => vm.ctx.none(),
|
||||
};
|
||||
ctx.set_attr(&node, "msg", py_msg);
|
||||
vm.ctx.set_attr(&node, "msg", py_msg);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Statement::Delete { targets } => {
|
||||
let node = create_node(ctx, "Delete");
|
||||
let node = create_node(vm, "Delete");
|
||||
|
||||
let py_targets =
|
||||
ctx.new_tuple(targets.iter().map(|v| expression_to_ast(ctx, v)).collect());
|
||||
ctx.set_attr(&node, "targets", py_targets);
|
||||
let py_targets = vm
|
||||
.ctx
|
||||
.new_tuple(targets.iter().map(|v| expression_to_ast(vm, v)).collect());
|
||||
vm.ctx.set_attr(&node, "targets", py_targets);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Statement::Return { value } => {
|
||||
let node = create_node(ctx, "Return");
|
||||
let node = create_node(vm, "Return");
|
||||
|
||||
let py_value = if let Some(value) = value {
|
||||
ctx.new_tuple(value.iter().map(|v| expression_to_ast(ctx, v)).collect())
|
||||
vm.ctx
|
||||
.new_tuple(value.iter().map(|v| expression_to_ast(vm, v)).collect())
|
||||
} else {
|
||||
ctx.none()
|
||||
vm.ctx.none()
|
||||
};
|
||||
ctx.set_attr(&node, "value", py_value);
|
||||
vm.ctx.set_attr(&node, "value", py_value);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Statement::If { test, body, orelse } => {
|
||||
let node = create_node(ctx, "If");
|
||||
let node = create_node(vm, "If");
|
||||
|
||||
let py_test = expression_to_ast(ctx, test);
|
||||
ctx.set_attr(&node, "test", py_test);
|
||||
let py_test = expression_to_ast(vm, test);
|
||||
vm.ctx.set_attr(&node, "test", py_test);
|
||||
|
||||
let py_body = statements_to_ast(ctx, body);
|
||||
ctx.set_attr(&node, "body", py_body);
|
||||
let py_body = statements_to_ast(vm, body);
|
||||
vm.ctx.set_attr(&node, "body", py_body);
|
||||
|
||||
let py_orelse = if let Some(orelse) = orelse {
|
||||
statements_to_ast(ctx, orelse)
|
||||
statements_to_ast(vm, orelse)
|
||||
} else {
|
||||
ctx.none()
|
||||
vm.ctx.none()
|
||||
};
|
||||
ctx.set_attr(&node, "orelse", py_orelse);
|
||||
vm.ctx.set_attr(&node, "orelse", py_orelse);
|
||||
|
||||
node
|
||||
}
|
||||
@@ -169,49 +184,49 @@ fn statement_to_ast(ctx: &PyContext, statement: &ast::LocatedStatement) -> PyObj
|
||||
body,
|
||||
orelse,
|
||||
} => {
|
||||
let node = create_node(ctx, "For");
|
||||
let node = create_node(vm, "For");
|
||||
|
||||
let py_target = expression_to_ast(ctx, target);
|
||||
ctx.set_attr(&node, "target", py_target);
|
||||
let py_target = expression_to_ast(vm, target);
|
||||
vm.ctx.set_attr(&node, "target", py_target);
|
||||
|
||||
let py_iter = expressions_to_ast(ctx, iter);
|
||||
ctx.set_attr(&node, "iter", py_iter);
|
||||
let py_iter = expressions_to_ast(vm, iter);
|
||||
vm.ctx.set_attr(&node, "iter", py_iter);
|
||||
|
||||
let py_body = statements_to_ast(ctx, body);
|
||||
ctx.set_attr(&node, "body", py_body);
|
||||
let py_body = statements_to_ast(vm, body);
|
||||
vm.ctx.set_attr(&node, "body", py_body);
|
||||
|
||||
let py_orelse = if let Some(orelse) = orelse {
|
||||
statements_to_ast(ctx, orelse)
|
||||
statements_to_ast(vm, orelse)
|
||||
} else {
|
||||
ctx.none()
|
||||
vm.ctx.none()
|
||||
};
|
||||
ctx.set_attr(&node, "orelse", py_orelse);
|
||||
vm.ctx.set_attr(&node, "orelse", py_orelse);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Statement::While { test, body, orelse } => {
|
||||
let node = create_node(ctx, "While");
|
||||
let node = create_node(vm, "While");
|
||||
|
||||
let py_test = expression_to_ast(ctx, test);
|
||||
ctx.set_attr(&node, "test", py_test);
|
||||
let py_test = expression_to_ast(vm, test);
|
||||
vm.ctx.set_attr(&node, "test", py_test);
|
||||
|
||||
let py_body = statements_to_ast(ctx, body);
|
||||
ctx.set_attr(&node, "body", py_body);
|
||||
let py_body = statements_to_ast(vm, body);
|
||||
vm.ctx.set_attr(&node, "body", py_body);
|
||||
|
||||
let py_orelse = if let Some(orelse) = orelse {
|
||||
statements_to_ast(ctx, orelse)
|
||||
statements_to_ast(vm, orelse)
|
||||
} else {
|
||||
ctx.none()
|
||||
vm.ctx.none()
|
||||
};
|
||||
ctx.set_attr(&node, "orelse", py_orelse);
|
||||
vm.ctx.set_attr(&node, "orelse", py_orelse);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Statement::Expression { expression } => {
|
||||
let node = create_node(ctx, "Expr");
|
||||
let node = create_node(vm, "Expr");
|
||||
|
||||
let value = expression_to_ast(ctx, expression);
|
||||
ctx.set_attr(&node, "value", value);
|
||||
let value = expression_to_ast(vm, expression);
|
||||
vm.ctx.set_attr(&node, "value", value);
|
||||
|
||||
node
|
||||
}
|
||||
@@ -221,38 +236,38 @@ fn statement_to_ast(ctx: &PyContext, statement: &ast::LocatedStatement) -> PyObj
|
||||
};
|
||||
|
||||
// set lineno on node:
|
||||
let lineno = ctx.new_int(statement.location.get_row());
|
||||
ctx.set_attr(&node, "lineno", lineno);
|
||||
let lineno = vm.ctx.new_int(statement.location.get_row());
|
||||
vm.ctx.set_attr(&node, "lineno", lineno);
|
||||
|
||||
node
|
||||
}
|
||||
|
||||
fn expressions_to_ast(ctx: &PyContext, expressions: &[ast::Expression]) -> PyObjectRef {
|
||||
fn expressions_to_ast(vm: &VirtualMachine, expressions: &[ast::Expression]) -> PyObjectRef {
|
||||
let mut py_expression_nodes = vec![];
|
||||
for expression in expressions {
|
||||
py_expression_nodes.push(expression_to_ast(ctx, expression));
|
||||
py_expression_nodes.push(expression_to_ast(vm, expression));
|
||||
}
|
||||
ctx.new_list(py_expression_nodes)
|
||||
vm.ctx.new_list(py_expression_nodes)
|
||||
}
|
||||
|
||||
fn expression_to_ast(ctx: &PyContext, expression: &ast::Expression) -> PyObjectRef {
|
||||
fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyObjectRef {
|
||||
let node = match &expression {
|
||||
ast::Expression::Call { function, args, .. } => {
|
||||
let node = create_node(ctx, "Call");
|
||||
let node = create_node(vm, "Call");
|
||||
|
||||
let py_func_ast = expression_to_ast(ctx, function);
|
||||
ctx.set_attr(&node, "func", py_func_ast);
|
||||
let py_func_ast = expression_to_ast(vm, function);
|
||||
vm.ctx.set_attr(&node, "func", py_func_ast);
|
||||
|
||||
let py_args = expressions_to_ast(ctx, args);
|
||||
ctx.set_attr(&node, "args", py_args);
|
||||
let py_args = expressions_to_ast(vm, args);
|
||||
vm.ctx.set_attr(&node, "args", py_args);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::Binop { a, op, b } => {
|
||||
let node = create_node(ctx, "BinOp");
|
||||
let node = create_node(vm, "BinOp");
|
||||
|
||||
let py_a = expression_to_ast(ctx, a);
|
||||
ctx.set_attr(&node, "left", py_a);
|
||||
let py_a = expression_to_ast(vm, a);
|
||||
vm.ctx.set_attr(&node, "left", py_a);
|
||||
|
||||
// Operator:
|
||||
let str_op = match op {
|
||||
@@ -270,15 +285,15 @@ fn expression_to_ast(ctx: &PyContext, expression: &ast::Expression) -> PyObjectR
|
||||
ast::Operator::BitAnd => "BitAnd",
|
||||
ast::Operator::FloorDiv => "FloorDiv",
|
||||
};
|
||||
let py_op = ctx.new_str(str_op.to_string());
|
||||
ctx.set_attr(&node, "op", py_op);
|
||||
let py_op = vm.ctx.new_str(str_op.to_string());
|
||||
vm.ctx.set_attr(&node, "op", py_op);
|
||||
|
||||
let py_b = expression_to_ast(ctx, b);
|
||||
ctx.set_attr(&node, "right", py_b);
|
||||
let py_b = expression_to_ast(vm, b);
|
||||
vm.ctx.set_attr(&node, "right", py_b);
|
||||
node
|
||||
}
|
||||
ast::Expression::Unop { op, a } => {
|
||||
let node = create_node(ctx, "UnaryOp");
|
||||
let node = create_node(vm, "UnaryOp");
|
||||
|
||||
let str_op = match op {
|
||||
ast::UnaryOperator::Not => "Not",
|
||||
@@ -286,37 +301,37 @@ fn expression_to_ast(ctx: &PyContext, expression: &ast::Expression) -> PyObjectR
|
||||
ast::UnaryOperator::Neg => "USub",
|
||||
ast::UnaryOperator::Pos => "UAdd",
|
||||
};
|
||||
let py_op = ctx.new_str(str_op.to_string());
|
||||
ctx.set_attr(&node, "op", py_op);
|
||||
let py_op = vm.ctx.new_str(str_op.to_string());
|
||||
vm.ctx.set_attr(&node, "op", py_op);
|
||||
|
||||
let py_a = expression_to_ast(ctx, a);
|
||||
ctx.set_attr(&node, "operand", py_a);
|
||||
let py_a = expression_to_ast(vm, a);
|
||||
vm.ctx.set_attr(&node, "operand", py_a);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::BoolOp { a, op, b } => {
|
||||
let node = create_node(ctx, "BoolOp");
|
||||
let node = create_node(vm, "BoolOp");
|
||||
|
||||
// Attach values:
|
||||
let py_a = expression_to_ast(ctx, a);
|
||||
let py_b = expression_to_ast(ctx, b);
|
||||
let py_values = ctx.new_tuple(vec![py_a, py_b]);
|
||||
ctx.set_attr(&node, "values", py_values);
|
||||
let py_a = expression_to_ast(vm, a);
|
||||
let py_b = expression_to_ast(vm, b);
|
||||
let py_values = vm.ctx.new_tuple(vec![py_a, py_b]);
|
||||
vm.ctx.set_attr(&node, "values", py_values);
|
||||
|
||||
let str_op = match op {
|
||||
ast::BooleanOperator::And => "And",
|
||||
ast::BooleanOperator::Or => "Or",
|
||||
};
|
||||
let py_op = ctx.new_str(str_op.to_string());
|
||||
ctx.set_attr(&node, "op", py_op);
|
||||
let py_op = vm.ctx.new_str(str_op.to_string());
|
||||
vm.ctx.set_attr(&node, "op", py_op);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::Compare { a, op, b } => {
|
||||
let node = create_node(ctx, "Compare");
|
||||
let node = create_node(vm, "Compare");
|
||||
|
||||
let py_a = expression_to_ast(ctx, a);
|
||||
ctx.set_attr(&node, "left", py_a);
|
||||
let py_a = expression_to_ast(vm, a);
|
||||
vm.ctx.set_attr(&node, "left", py_a);
|
||||
|
||||
// Operator:
|
||||
let str_op = match op {
|
||||
@@ -331,282 +346,283 @@ fn expression_to_ast(ctx: &PyContext, expression: &ast::Expression) -> PyObjectR
|
||||
ast::Comparison::Is => "Is",
|
||||
ast::Comparison::IsNot => "IsNot",
|
||||
};
|
||||
let py_ops = ctx.new_list(vec![ctx.new_str(str_op.to_string())]);
|
||||
ctx.set_attr(&node, "ops", py_ops);
|
||||
let py_ops = vm.ctx.new_list(vec![vm.ctx.new_str(str_op.to_string())]);
|
||||
vm.ctx.set_attr(&node, "ops", py_ops);
|
||||
|
||||
let py_b = ctx.new_list(vec![expression_to_ast(ctx, b)]);
|
||||
ctx.set_attr(&node, "comparators", py_b);
|
||||
let py_b = vm.ctx.new_list(vec![expression_to_ast(vm, b)]);
|
||||
vm.ctx.set_attr(&node, "comparators", py_b);
|
||||
node
|
||||
}
|
||||
ast::Expression::Identifier { name } => {
|
||||
let node = create_node(ctx, "Identifier");
|
||||
let node = create_node(vm, "Identifier");
|
||||
|
||||
// Id:
|
||||
let py_name = ctx.new_str(name.clone());
|
||||
ctx.set_attr(&node, "id", py_name);
|
||||
let py_name = vm.ctx.new_str(name.clone());
|
||||
vm.ctx.set_attr(&node, "id", py_name);
|
||||
node
|
||||
}
|
||||
ast::Expression::Lambda { args, body } => {
|
||||
let node = create_node(ctx, "Lambda");
|
||||
let node = create_node(vm, "Lambda");
|
||||
|
||||
ctx.set_attr(&node, "args", parameters_to_ast(ctx, args));
|
||||
vm.ctx.set_attr(&node, "args", parameters_to_ast(vm, args));
|
||||
|
||||
let py_body = expression_to_ast(ctx, body);
|
||||
ctx.set_attr(&node, "body", py_body);
|
||||
let py_body = expression_to_ast(vm, body);
|
||||
vm.ctx.set_attr(&node, "body", py_body);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::IfExpression { test, body, orelse } => {
|
||||
let node = create_node(ctx, "IfExp");
|
||||
let node = create_node(vm, "IfExp");
|
||||
|
||||
let py_test = expression_to_ast(ctx, test);
|
||||
ctx.set_attr(&node, "test", py_test);
|
||||
let py_test = expression_to_ast(vm, test);
|
||||
vm.ctx.set_attr(&node, "test", py_test);
|
||||
|
||||
let py_body = expression_to_ast(ctx, body);
|
||||
ctx.set_attr(&node, "body", py_body);
|
||||
let py_body = expression_to_ast(vm, body);
|
||||
vm.ctx.set_attr(&node, "body", py_body);
|
||||
|
||||
let py_orelse = expression_to_ast(ctx, orelse);
|
||||
ctx.set_attr(&node, "orelse", py_orelse);
|
||||
let py_orelse = expression_to_ast(vm, orelse);
|
||||
vm.ctx.set_attr(&node, "orelse", py_orelse);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::Number { value } => {
|
||||
let node = create_node(ctx, "Num");
|
||||
let node = create_node(vm, "Num");
|
||||
|
||||
let py_n = match value {
|
||||
ast::Number::Integer { value } => ctx.new_int(value.clone()),
|
||||
ast::Number::Float { value } => ctx.new_float(*value),
|
||||
ast::Number::Integer { value } => vm.ctx.new_int(value.clone()),
|
||||
ast::Number::Float { value } => vm.ctx.new_float(*value),
|
||||
ast::Number::Complex { real, imag } => {
|
||||
ctx.new_complex(Complex64::new(*real, *imag))
|
||||
vm.ctx.new_complex(Complex64::new(*real, *imag))
|
||||
}
|
||||
};
|
||||
ctx.set_attr(&node, "n", py_n);
|
||||
vm.ctx.set_attr(&node, "n", py_n);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::True => {
|
||||
let node = create_node(ctx, "NameConstant");
|
||||
let node = create_node(vm, "NameConstant");
|
||||
|
||||
ctx.set_attr(&node, "value", ctx.new_bool(true));
|
||||
vm.ctx.set_attr(&node, "value", vm.ctx.new_bool(true));
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::False => {
|
||||
let node = create_node(ctx, "NameConstant");
|
||||
let node = create_node(vm, "NameConstant");
|
||||
|
||||
ctx.set_attr(&node, "value", ctx.new_bool(false));
|
||||
vm.ctx.set_attr(&node, "value", vm.ctx.new_bool(false));
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::None => {
|
||||
let node = create_node(ctx, "NameConstant");
|
||||
let node = create_node(vm, "NameConstant");
|
||||
|
||||
ctx.set_attr(&node, "value", ctx.none());
|
||||
vm.ctx.set_attr(&node, "value", vm.ctx.none());
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::Ellipsis => create_node(ctx, "Ellipsis"),
|
||||
ast::Expression::Ellipsis => create_node(vm, "Ellipsis"),
|
||||
ast::Expression::List { elements } => {
|
||||
let node = create_node(ctx, "List");
|
||||
let node = create_node(vm, "List");
|
||||
|
||||
let elts = elements.iter().map(|e| expression_to_ast(ctx, e)).collect();
|
||||
let py_elts = ctx.new_list(elts);
|
||||
ctx.set_attr(&node, "elts", py_elts);
|
||||
let elts = elements.iter().map(|e| expression_to_ast(vm, e)).collect();
|
||||
let py_elts = vm.ctx.new_list(elts);
|
||||
vm.ctx.set_attr(&node, "elts", py_elts);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::Tuple { elements } => {
|
||||
let node = create_node(ctx, "Tuple");
|
||||
let node = create_node(vm, "Tuple");
|
||||
|
||||
let elts = elements.iter().map(|e| expression_to_ast(ctx, e)).collect();
|
||||
let py_elts = ctx.new_list(elts);
|
||||
ctx.set_attr(&node, "elts", py_elts);
|
||||
let elts = elements.iter().map(|e| expression_to_ast(vm, e)).collect();
|
||||
let py_elts = vm.ctx.new_list(elts);
|
||||
vm.ctx.set_attr(&node, "elts", py_elts);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::Set { elements } => {
|
||||
let node = create_node(ctx, "Set");
|
||||
let node = create_node(vm, "Set");
|
||||
|
||||
let elts = elements.iter().map(|e| expression_to_ast(ctx, e)).collect();
|
||||
let py_elts = ctx.new_list(elts);
|
||||
ctx.set_attr(&node, "elts", py_elts);
|
||||
let elts = elements.iter().map(|e| expression_to_ast(vm, e)).collect();
|
||||
let py_elts = vm.ctx.new_list(elts);
|
||||
vm.ctx.set_attr(&node, "elts", py_elts);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::Dict { elements } => {
|
||||
let node = create_node(ctx, "Dict");
|
||||
let node = create_node(vm, "Dict");
|
||||
|
||||
let mut keys = Vec::new();
|
||||
let mut values = Vec::new();
|
||||
for (k, v) in elements {
|
||||
keys.push(expression_to_ast(ctx, k));
|
||||
values.push(expression_to_ast(ctx, v));
|
||||
keys.push(expression_to_ast(vm, k));
|
||||
values.push(expression_to_ast(vm, v));
|
||||
}
|
||||
|
||||
let py_keys = ctx.new_list(keys);
|
||||
ctx.set_attr(&node, "keys", py_keys);
|
||||
let py_keys = vm.ctx.new_list(keys);
|
||||
vm.ctx.set_attr(&node, "keys", py_keys);
|
||||
|
||||
let py_values = ctx.new_list(values);
|
||||
ctx.set_attr(&node, "values", py_values);
|
||||
let py_values = vm.ctx.new_list(values);
|
||||
vm.ctx.set_attr(&node, "values", py_values);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::Comprehension { kind, generators } => {
|
||||
let node = match kind.deref() {
|
||||
ast::ComprehensionKind::GeneratorExpression { .. } => {
|
||||
create_node(ctx, "GeneratorExp")
|
||||
create_node(vm, "GeneratorExp")
|
||||
}
|
||||
ast::ComprehensionKind::List { .. } => create_node(ctx, "ListComp"),
|
||||
ast::ComprehensionKind::Set { .. } => create_node(ctx, "SetComp"),
|
||||
ast::ComprehensionKind::Dict { .. } => create_node(ctx, "DictComp"),
|
||||
ast::ComprehensionKind::List { .. } => create_node(vm, "ListComp"),
|
||||
ast::ComprehensionKind::Set { .. } => create_node(vm, "SetComp"),
|
||||
ast::ComprehensionKind::Dict { .. } => create_node(vm, "DictComp"),
|
||||
};
|
||||
|
||||
let g = generators
|
||||
.iter()
|
||||
.map(|g| comprehension_to_ast(ctx, g))
|
||||
.map(|g| comprehension_to_ast(vm, g))
|
||||
.collect();
|
||||
let py_generators = ctx.new_list(g);
|
||||
ctx.set_attr(&node, "generators", py_generators);
|
||||
let py_generators = vm.ctx.new_list(g);
|
||||
vm.ctx.set_attr(&node, "generators", py_generators);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::Yield { value } => {
|
||||
let node = create_node(ctx, "Yield");
|
||||
let node = create_node(vm, "Yield");
|
||||
|
||||
let py_value = match value {
|
||||
Some(value) => expression_to_ast(ctx, value),
|
||||
None => ctx.none(),
|
||||
Some(value) => expression_to_ast(vm, value),
|
||||
None => vm.ctx.none(),
|
||||
};
|
||||
ctx.set_attr(&node, "value", py_value);
|
||||
vm.ctx.set_attr(&node, "value", py_value);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::YieldFrom { value } => {
|
||||
let node = create_node(ctx, "YieldFrom");
|
||||
let node = create_node(vm, "YieldFrom");
|
||||
|
||||
let py_value = expression_to_ast(ctx, value);
|
||||
ctx.set_attr(&node, "value", py_value);
|
||||
let py_value = expression_to_ast(vm, value);
|
||||
vm.ctx.set_attr(&node, "value", py_value);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::Subscript { a, b } => {
|
||||
let node = create_node(ctx, "Subscript");
|
||||
let node = create_node(vm, "Subscript");
|
||||
|
||||
let py_value = expression_to_ast(ctx, a);
|
||||
ctx.set_attr(&node, "value", py_value);
|
||||
let py_value = expression_to_ast(vm, a);
|
||||
vm.ctx.set_attr(&node, "value", py_value);
|
||||
|
||||
let py_slice = expression_to_ast(ctx, b);
|
||||
ctx.set_attr(&node, "slice", py_slice);
|
||||
let py_slice = expression_to_ast(vm, b);
|
||||
vm.ctx.set_attr(&node, "slice", py_slice);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::Attribute { value, name } => {
|
||||
let node = create_node(ctx, "Attribute");
|
||||
let node = create_node(vm, "Attribute");
|
||||
|
||||
let py_value = expression_to_ast(ctx, value);
|
||||
ctx.set_attr(&node, "value", py_value);
|
||||
let py_value = expression_to_ast(vm, value);
|
||||
vm.ctx.set_attr(&node, "value", py_value);
|
||||
|
||||
let py_attr = ctx.new_str(name.to_string());
|
||||
ctx.set_attr(&node, "attr", py_attr);
|
||||
let py_attr = vm.ctx.new_str(name.to_string());
|
||||
vm.ctx.set_attr(&node, "attr", py_attr);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::Starred { value } => {
|
||||
let node = create_node(ctx, "Starred");
|
||||
let node = create_node(vm, "Starred");
|
||||
|
||||
let py_value = expression_to_ast(ctx, value);
|
||||
ctx.set_attr(&node, "value", py_value);
|
||||
let py_value = expression_to_ast(vm, value);
|
||||
vm.ctx.set_attr(&node, "value", py_value);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::Slice { elements } => {
|
||||
let node = create_node(ctx, "Slice");
|
||||
let node = create_node(vm, "Slice");
|
||||
|
||||
let py_value = expressions_to_ast(ctx, elements);
|
||||
ctx.set_attr(&node, "bounds", py_value);
|
||||
let py_value = expressions_to_ast(vm, elements);
|
||||
vm.ctx.set_attr(&node, "bounds", py_value);
|
||||
|
||||
node
|
||||
}
|
||||
ast::Expression::String { value } => string_to_ast(ctx, value),
|
||||
ast::Expression::String { value } => string_to_ast(vm, value),
|
||||
ast::Expression::Bytes { value } => {
|
||||
let node = create_node(ctx, "Bytes");
|
||||
ctx.set_attr(&node, "s", ctx.new_bytes(value.clone()));
|
||||
let node = create_node(vm, "Bytes");
|
||||
vm.ctx.set_attr(&node, "s", vm.ctx.new_bytes(value.clone()));
|
||||
node
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: retrieve correct lineno:
|
||||
let lineno = ctx.new_int(1);
|
||||
ctx.set_attr(&node, "lineno", lineno);
|
||||
let lineno = vm.ctx.new_int(1);
|
||||
vm.ctx.set_attr(&node, "lineno", lineno);
|
||||
|
||||
node
|
||||
}
|
||||
|
||||
fn parameters_to_ast(ctx: &PyContext, args: &ast::Parameters) -> PyObjectRef {
|
||||
let node = create_node(ctx, "arguments");
|
||||
fn parameters_to_ast(vm: &VirtualMachine, args: &ast::Parameters) -> PyObjectRef {
|
||||
let node = create_node(vm, "arguments");
|
||||
|
||||
ctx.set_attr(
|
||||
vm.ctx.set_attr(
|
||||
&node,
|
||||
"args",
|
||||
ctx.new_list(args.args.iter().map(|a| parameter_to_ast(ctx, a)).collect()),
|
||||
vm.ctx
|
||||
.new_list(args.args.iter().map(|a| parameter_to_ast(vm, a)).collect()),
|
||||
);
|
||||
|
||||
node
|
||||
}
|
||||
|
||||
fn parameter_to_ast(ctx: &PyContext, parameter: &ast::Parameter) -> PyObjectRef {
|
||||
let node = create_node(ctx, "arg");
|
||||
fn parameter_to_ast(vm: &VirtualMachine, parameter: &ast::Parameter) -> PyObjectRef {
|
||||
let node = create_node(vm, "arg");
|
||||
|
||||
let py_arg = ctx.new_str(parameter.arg.to_string());
|
||||
ctx.set_attr(&node, "arg", py_arg);
|
||||
let py_arg = vm.ctx.new_str(parameter.arg.to_string());
|
||||
vm.ctx.set_attr(&node, "arg", py_arg);
|
||||
|
||||
let py_annotation = if let Some(annotation) = ¶meter.annotation {
|
||||
expression_to_ast(ctx, annotation)
|
||||
expression_to_ast(vm, annotation)
|
||||
} else {
|
||||
ctx.none()
|
||||
vm.ctx.none()
|
||||
};
|
||||
ctx.set_attr(&node, "annotation", py_annotation);
|
||||
vm.ctx.set_attr(&node, "annotation", py_annotation);
|
||||
|
||||
node
|
||||
}
|
||||
|
||||
fn comprehension_to_ast(ctx: &PyContext, comprehension: &ast::Comprehension) -> PyObjectRef {
|
||||
let node = create_node(ctx, "comprehension");
|
||||
fn comprehension_to_ast(vm: &VirtualMachine, comprehension: &ast::Comprehension) -> PyObjectRef {
|
||||
let node = create_node(vm, "comprehension");
|
||||
|
||||
let py_target = expression_to_ast(ctx, &comprehension.target);
|
||||
ctx.set_attr(&node, "target", py_target);
|
||||
let py_target = expression_to_ast(vm, &comprehension.target);
|
||||
vm.ctx.set_attr(&node, "target", py_target);
|
||||
|
||||
let py_iter = expression_to_ast(ctx, &comprehension.iter);
|
||||
ctx.set_attr(&node, "iter", py_iter);
|
||||
let py_iter = expression_to_ast(vm, &comprehension.iter);
|
||||
vm.ctx.set_attr(&node, "iter", py_iter);
|
||||
|
||||
let py_ifs = expressions_to_ast(ctx, &comprehension.ifs);
|
||||
ctx.set_attr(&node, "ifs", py_ifs);
|
||||
let py_ifs = expressions_to_ast(vm, &comprehension.ifs);
|
||||
vm.ctx.set_attr(&node, "ifs", py_ifs);
|
||||
|
||||
node
|
||||
}
|
||||
|
||||
fn string_to_ast(ctx: &PyContext, string: &ast::StringGroup) -> PyObjectRef {
|
||||
fn string_to_ast(vm: &VirtualMachine, string: &ast::StringGroup) -> PyObjectRef {
|
||||
match string {
|
||||
ast::StringGroup::Constant { value } => {
|
||||
let node = create_node(ctx, "Str");
|
||||
ctx.set_attr(&node, "s", ctx.new_str(value.clone()));
|
||||
let node = create_node(vm, "Str");
|
||||
vm.ctx.set_attr(&node, "s", vm.ctx.new_str(value.clone()));
|
||||
node
|
||||
}
|
||||
ast::StringGroup::FormattedValue { value, .. } => {
|
||||
let node = create_node(ctx, "FormattedValue");
|
||||
let py_value = expression_to_ast(ctx, value);
|
||||
ctx.set_attr(&node, "value", py_value);
|
||||
let node = create_node(vm, "FormattedValue");
|
||||
let py_value = expression_to_ast(vm, value);
|
||||
vm.ctx.set_attr(&node, "value", py_value);
|
||||
node
|
||||
}
|
||||
ast::StringGroup::Joined { values } => {
|
||||
let node = create_node(ctx, "JoinedStr");
|
||||
let py_values = ctx.new_list(
|
||||
let node = create_node(vm, "JoinedStr");
|
||||
let py_values = vm.ctx.new_list(
|
||||
values
|
||||
.iter()
|
||||
.map(|value| string_to_ast(ctx, value))
|
||||
.map(|value| string_to_ast(vm, value))
|
||||
.collect(),
|
||||
);
|
||||
ctx.set_attr(&node, "values", py_values);
|
||||
vm.ctx.set_attr(&node, "values", py_values);
|
||||
node
|
||||
}
|
||||
}
|
||||
@@ -619,7 +635,7 @@ fn ast_parse(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
let internal_ast = parser::parse_program(&source_string)
|
||||
.map_err(|err| vm.new_value_error(format!("{}", err)))?;
|
||||
// source.clone();
|
||||
let ast_node = program_to_ast(&vm.ctx, &internal_ast);
|
||||
let ast_node = program_to_ast(&vm, &internal_ast);
|
||||
Ok(ast_node)
|
||||
}
|
||||
|
||||
@@ -628,6 +644,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
|
||||
"parse" => ctx.new_rustfunc(ast_parse),
|
||||
"Module" => py_class!(ctx, "_ast.Module", ctx.object(), {}),
|
||||
"FunctionDef" => py_class!(ctx, "_ast.FunctionDef", ctx.object(), {}),
|
||||
"Call" => py_class!(ctx, "_ast.Call", ctx.object(), {})
|
||||
"Call" => py_class!(ctx, "_ast.Call", ctx.object(), {}),
|
||||
"AST" => py_class!(ctx, "_ast.AST", ctx.object(), {}),
|
||||
})
|
||||
}
|
||||
@@ -177,7 +177,7 @@ impl<'de> Visitor<'de> for PyObjectDeserializer<'de> {
|
||||
};
|
||||
dict.set_item(&self.vm.ctx, &key, value);
|
||||
}
|
||||
Ok(dict)
|
||||
Ok(dict.into_object())
|
||||
}
|
||||
|
||||
fn visit_unit<E>(self) -> Result<Self::Value, E>
|
||||
|
||||
+2
-6
@@ -141,10 +141,6 @@ impl VirtualMachine {
|
||||
self.ctx.new_bool(b)
|
||||
}
|
||||
|
||||
pub fn new_dict(&self) -> PyObjectRef {
|
||||
self.ctx.new_dict()
|
||||
}
|
||||
|
||||
pub fn new_empty_exception(&self, exc_type: PyClassRef) -> PyResult {
|
||||
info!("New exception created: no msg");
|
||||
let args = PyFuncArgs::default();
|
||||
@@ -454,11 +450,11 @@ impl VirtualMachine {
|
||||
// Do we support `**kwargs` ?
|
||||
let kwargs = match code_object.varkeywords {
|
||||
bytecode::Varargs::Named(ref kwargs_name) => {
|
||||
let d = self.new_dict();
|
||||
let d = self.ctx.new_dict().into_object();
|
||||
locals.set_item(&self.ctx, kwargs_name, d.clone());
|
||||
Some(d)
|
||||
}
|
||||
bytecode::Varargs::Unnamed => Some(self.new_dict()),
|
||||
bytecode::Varargs::Unnamed => Some(self.ctx.new_dict().into_object()),
|
||||
bytecode::Varargs::None => None,
|
||||
};
|
||||
|
||||
|
||||
@@ -363,6 +363,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
|
||||
doc: window().document().expect("Document missing from window"),
|
||||
},
|
||||
document_class.clone(),
|
||||
None,
|
||||
);
|
||||
|
||||
let element = py_class!(ctx, "Element", ctx.object(), {
|
||||
|
||||
@@ -188,13 +188,13 @@ pub fn js_to_py(vm: &VirtualMachine, js_val: JsValue) -> PyObjectRef {
|
||||
u8_array.copy_to(&mut vec);
|
||||
vm.ctx.new_bytes(vec)
|
||||
} else {
|
||||
let dict = vm.new_dict();
|
||||
let dict = vm.ctx.new_dict();
|
||||
for pair in object_entries(&Object::from(js_val)) {
|
||||
let (key, val) = pair.expect("iteration over object to not fail");
|
||||
let py_val = js_to_py(vm, val);
|
||||
dict.set_item(&vm.ctx, &String::from(js_sys::JsString::from(key)), py_val);
|
||||
}
|
||||
dict
|
||||
dict.into_object()
|
||||
}
|
||||
} else if js_val.is_function() {
|
||||
let func = js_sys::Function::from(js_val);
|
||||
|
||||
Reference in new issue
Block a user