From ac3da8b453fdf554b67d07337c67a9999fd88141 Mon Sep 17 00:00:00 2001 From: Gitea Date: Sat, 22 Dec 2018 00:47:19 -0500 Subject: [PATCH] Add 'from x import *' syntax. This is a separate opcode in CPython so I added it as such here. --- tests/snippets/import.py | 3 +++ tests/snippets/import_star.py | 3 +++ vm/src/bytecode.rs | 3 +++ vm/src/compile.rs | 35 ++++++++++++++++++++++------------- vm/src/frame.rs | 23 ++++++++++++++++++++++- vm/src/pyobject.rs | 12 +++++++++++- 6 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 tests/snippets/import_star.py diff --git a/tests/snippets/import.py b/tests/snippets/import.py index 46b8be387..1a5130269 100644 --- a/tests/snippets/import.py +++ b/tests/snippets/import.py @@ -1,6 +1,7 @@ import import_target, import_target as aliased from import_target import func, other_func from import_target import func as aliased_func, other_func as aliased_other_func +from import_star import * assert import_target.X == import_target.func() assert import_target.X == func() @@ -13,6 +14,8 @@ assert import_target.Y == aliased.Y assert import_target.X == aliased_func() assert import_target.Y == aliased_other_func() +assert STAR_IMPORT == '123' + # TODO: Once we can determine current directory, use that to construct this # path: #import sys diff --git a/tests/snippets/import_star.py b/tests/snippets/import_star.py new file mode 100644 index 000000000..efe23426f --- /dev/null +++ b/tests/snippets/import_star.py @@ -0,0 +1,3 @@ +# This is used by import.py; the two should be modified in concert + +STAR_IMPORT = '123' diff --git a/vm/src/bytecode.rs b/vm/src/bytecode.rs index 2cae6d30b..0c08d0d1b 100644 --- a/vm/src/bytecode.rs +++ b/vm/src/bytecode.rs @@ -66,6 +66,9 @@ pub enum Instruction { name: String, symbol: Option, }, + ImportStar { + name: String, + }, LoadName { name: String, }, diff --git a/vm/src/compile.rs b/vm/src/compile.rs index 8aa37d550..6c00a6467 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -156,19 +156,28 @@ impl Compiler { alias, } in import_parts { - self.emit(Instruction::Import { - name: module.clone(), - symbol: symbol.clone().map(|s| s.clone()), - }); - self.emit(Instruction::StoreName { - name: match alias { - Some(alias) => alias.clone(), - None => match symbol { - Some(symbol) => symbol.clone(), - None => module.clone(), - }, - }, - }); + match symbol { + Some(name) if name == "*" => { + self.emit(Instruction::ImportStar { + name: module.clone(), + }); + } + _ => { + self.emit(Instruction::Import { + name: module.clone(), + symbol: symbol.clone().map(|s| s.clone()), + }); + self.emit(Instruction::StoreName { + name: match alias { + Some(alias) => alias.clone(), + None => match symbol { + Some(symbol) => symbol.clone(), + None => module.clone(), + }, + }, + }); + } + } } } ast::Statement::Expression { expression } => { diff --git a/vm/src/frame.rs b/vm/src/frame.rs index b056ded7b..19fa17bd7 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; use super::builtins; use super::bytecode; -use super::import::import; +use super::import::{import, import_module}; use super::obj::objbool; use super::obj::objcode; use super::obj::objdict; @@ -182,6 +182,7 @@ impl Frame { ref name, ref symbol, } => self.import(vm, name, symbol), + bytecode::Instruction::ImportStar { ref name } => self.import_star(vm, name), bytecode::Instruction::LoadName { ref name } => self.load_name(vm, name), bytecode::Instruction::StoreName { ref name } => self.store_name(vm, name), bytecode::Instruction::DeleteName { ref name } => self.delete_name(vm, name), @@ -677,6 +678,26 @@ impl Frame { Ok(None) } + fn import_star(&mut self, vm: &mut VirtualMachine, module: &str) -> FrameResult { + let current_path = match &self.code.source_path { + Some(source_path) => { + let mut source_pathbuf = PathBuf::from(source_path); + source_pathbuf.pop(); + source_pathbuf + } + None => PathBuf::from("."), + }; + + // Grab all the names from the module and put them in the context + let obj = import_module(vm, current_path, module)?; + + for (k, v) in obj.get_key_value_pairs().iter() { + vm.ctx + .set_item(&self.locals, &objstr::get_value(k), v.clone()); + } + Ok(None) + } + // Unwind all blocks: fn unwind_blocks(&mut self, vm: &mut VirtualMachine) -> Option { loop { diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 3ef4ab282..6e21c269e 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -25,7 +25,7 @@ use super::vm::VirtualMachine; use num_bigint::BigInt; use num_complex::Complex64; use num_traits::{One, Zero}; -use std::cell::RefCell; +use std::cell::{Ref, RefCell}; use std::collections::HashMap; use std::fmt; use std::rc::{Rc, Weak}; @@ -681,6 +681,7 @@ impl AttributeProtocol for PyObjectRef { pub trait DictProtocol { fn contains_key(&self, k: &str) -> bool; fn get_item(&self, k: &str) -> Option; + fn get_key_value_pairs(&self) -> Vec<(PyObjectRef, PyObjectRef)>; } impl DictProtocol for PyObjectRef { @@ -701,6 +702,15 @@ impl DictProtocol for PyObjectRef { _ => panic!("TODO"), } } + + fn get_key_value_pairs(&self) -> Vec<(PyObjectRef, PyObjectRef)> { + match self.borrow().kind { + PyObjectKind::Dict { elements: _ } => objdict::get_key_value_pairs(self), + PyObjectKind::Module { name: _, ref dict } => dict.get_key_value_pairs(), + PyObjectKind::Scope { ref scope } => scope.locals.get_key_value_pairs(), + _ => panic!("TODO"), + } + } } impl fmt::Debug for PyObject {