Merge branch 'master' into coolreader18/update-deps

This commit is contained in:
coolreader18 committed 2019-03-25 21:41:32 -04:00
commit e819ca6b87
33 files changed
+1342 -1154

No files matched your search

Generated
+43
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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();
+1 -1
View File
@@ -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
-2
View File
@@ -1,2 +0,0 @@
x = []
x.append(1)
+4
View File
@@ -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
+85
View File
@@ -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])
+8
View File
@@ -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)
+13
View File
@@ -0,0 +1,13 @@
# Test the unicode support! 👋
ᚴ=2
assert ᚴ*8 == 16
ᚴ="👋"
c = ᚴ*3
assert c == '👋👋👋'
-7
View File
@@ -1,7 +0,0 @@
word = "Python"
word[0] = "J" # Should raise a error, immutable
word[2:] = "Jy" # Should raise a error, immutable
+12 -12
View File
@@ -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
View File
@@ -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
View File
@@ -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)
}
+9
View File
@@ -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
View File
@@ -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))
}
+2 -2
View File
@@ -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
View File
@@ -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),
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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());
}
}
+2 -2
View File
@@ -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
View File
@@ -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))
}
+3 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) = &parameter.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(), {}),
})
}
+1 -1
View File
@@ -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
View File
@@ -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,
};
+1
View File
@@ -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(), {
+2 -2
View File
@@ -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);