Skip to content

Commit 2cb1949

Browse files
committed
Fix relative imports in VM and properly promote compiler errorsg
1 parent 553b29f commit 2cb1949

13 files changed

Lines changed: 153 additions & 104 deletions

File tree

src/bytecode_vm/compiler/compiler.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,15 @@ mod stmt;
1717

1818
/// A Python bytecode compiler.
1919
pub struct Compiler {
20+
/// Track the filename so we can associate it with later `CodeObjects`.
2021
filename: String,
22+
23+
/// Track the module name so we can associate it with later `CodeObjects`.
2124
module_name: ModuleName,
2225

26+
/// We must know the package name for relative imports to work.
27+
package: ModuleName,
28+
2329
/// Keep a reference to the code object being constructed so we can associate things with it,
2430
/// (variable names, constants, etc.).
2531
code_stack: Vec<CodeObject>,
@@ -29,10 +35,11 @@ pub struct Compiler {
2935
}
3036

3137
impl Compiler {
32-
pub fn new(module_name: &ModuleName, filename: &str) -> Self {
38+
pub fn new(module_name: &ModuleName, package: &ModuleName, filename: &str) -> Self {
3339
Self {
3440
filename: filename.to_string(),
3541
module_name: module_name.clone(),
42+
package: package.clone(),
3643
code_stack: vec![],
3744
line_number: 0,
3845
}
@@ -965,7 +972,8 @@ from .outer import foo
965972
from .outer import foo
966973
"#;
967974
let module_name = ModuleName::from_segments(&["pkg", "mod"]);
968-
let code = compile_at_module(text, module_name.clone());
975+
let pkg = ModuleName::from_segments(&["pkg"]);
976+
let code = compile_at_pkg(text, module_name.clone(), pkg);
969977

970978
let expected = CodeObject {
971979
module_name,
@@ -994,7 +1002,8 @@ from .outer import foo
9941002
from .outer.inner import foo
9951003
"#;
9961004
let module_name = ModuleName::from_segments(&["pkg", "mod"]);
997-
let code = compile_at_module(text, module_name.clone());
1005+
let pkg = ModuleName::from_segments(&["pkg"]);
1006+
let code = compile_at_pkg(text, module_name.clone(), pkg);
9981007

9991008
let expected = CodeObject {
10001009
module_name,
@@ -1023,7 +1032,8 @@ from .outer.inner import foo
10231032
from ..outer import foo
10241033
"#;
10251034
let module_name = ModuleName::from_segments(&["pkg", "mod"]);
1026-
let err = compile_err_at_module(text, module_name);
1035+
let pkg = ModuleName::from_segments(&["pkg"]);
1036+
let err = compile_err_at_pkg(text, module_name, pkg);
10271037

10281038
match err {
10291039
CompilerError::ImportError(msg) => assert_eq!(

src/bytecode_vm/compiler/compiler/stmt.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{
33
compiler::{opcode::UnsignedOffset, CodeObject, Constant, Opcode},
44
Compiler, CompilerError, CompilerResult,
55
},
6-
domain::{resolve_import_path, FromImportPath, FunctionType, Identifier, ModuleName},
6+
domain::{resolve_import_path, FromImportPath, FunctionType, Identifier},
77
parser::types::{
88
Ast, ConditionalAst, Expr, FromImportMode, LoopIndex, Params, RegularImport, Statement,
99
StatementKind,
@@ -334,9 +334,7 @@ impl Compiler {
334334
import_path: &FromImportPath,
335335
mode: &FromImportMode,
336336
) -> CompilerResult<()> {
337-
// TODO pass the real package here, we're not detecting __init__ here at the moment
338-
let package = self.module_name.parent().unwrap_or(ModuleName::empty());
339-
let module_name = resolve_import_path(import_path, &package)
337+
let module_name = resolve_import_path(import_path, &self.package)
340338
.map_err(|e| CompilerError::import_error(e.message()))?;
341339

342340
let index = self.get_or_set_nonlocal_index(&module_name.as_str())?;

src/bytecode_vm/compiler/error.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::fmt::{Display, Error, Formatter};
1+
use crate::bytecode_vm::{runtime::types::Exception, VirtualMachine};
22

33
#[derive(Clone, PartialEq, Debug)]
44
pub enum CompilerError {
@@ -12,15 +12,13 @@ impl CompilerError {
1212
pub fn import_error(msg: impl Into<String>) -> Self {
1313
Self::ImportError(msg.into())
1414
}
15-
}
1615

17-
impl Display for CompilerError {
18-
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
16+
pub fn into_exception(self, vm: &mut VirtualMachine) -> Exception {
1917
match self {
20-
Self::Unsupported(msg) => write!(f, "Unsupported feature: {msg}"),
21-
Self::SyntaxError(msg) => write!(f, "Syntax error: {msg}"),
22-
Self::Internal(msg) => write!(f, "Internal error: {msg}"),
23-
Self::ImportError(msg) => write!(f, "ImportError: {msg}"),
18+
CompilerError::SyntaxError(msg) => Exception::syntax_error(vm.intern_string(&msg)),
19+
CompilerError::ImportError(msg) => Exception::import_error(vm.intern_string(&msg)),
20+
CompilerError::Unsupported(msg) => Exception::syntax_error(vm.intern_string(&msg)),
21+
CompilerError::Internal(msg) => Exception::syntax_error(vm.intern_string(&msg)),
2422
}
2523
}
2624
}

src/bytecode_vm/compiler/test_utils.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ use crate::{
1212
};
1313

1414
fn init() -> Compiler {
15-
Compiler::new(&ModuleName::main(), "compiler_unit_test")
15+
Compiler::new(
16+
&ModuleName::main(),
17+
&ModuleName::empty(),
18+
"compiler_unit_test",
19+
)
1620
}
1721

1822
fn init_ctx(text: &str) -> VmContext {
@@ -34,9 +38,10 @@ pub fn compile(text: &str) -> CodeObject {
3438
.expect("Failed to compile test program!")
3539
}
3640

37-
pub fn compile_at_module(text: &str, module_name: ModuleName) -> CodeObject {
41+
pub fn compile_at_pkg(text: &str, module: ModuleName, pkg: ModuleName) -> CodeObject {
3842
let mut ctx = init_ctx(text);
39-
ctx.set_module_name(module_name);
43+
ctx.set_module(module);
44+
ctx.set_pkg(pkg);
4045
ctx.compile().expect("Failed to compile test program!")
4146
}
4247

@@ -47,9 +52,10 @@ pub fn compile_err(text: &str) -> CompilerError {
4752
}
4853
}
4954

50-
pub fn compile_err_at_module(text: &str, module_name: ModuleName) -> CompilerError {
55+
pub fn compile_err_at_pkg(text: &str, module: ModuleName, pkg: ModuleName) -> CompilerError {
5156
let mut ctx = init_ctx(text);
52-
ctx.set_module_name(module_name);
57+
ctx.set_module(module);
58+
ctx.set_pkg(pkg);
5359
match ctx.compile() {
5460
Ok(_) => panic!("Expected an CompilerError!"),
5561
Err(e) => e,

src/bytecode_vm/context.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
use crate::domain::Source;
33
use crate::{
44
bytecode_vm::{
5-
compiler::CodeObject, runtime::types::Exception, Compiler, CompilerError, Runtime,
6-
VirtualMachine, VmResult, VmValue,
5+
compiler::CodeObject, Compiler, CompilerError, Runtime, VirtualMachine, VmResult, VmValue,
76
},
87
core::{Container, Interpreter},
98
domain::{MemphisResult, MemphisValue, ModuleName, ModuleOrigin, Text},
@@ -15,6 +14,7 @@ use crate::{
1514
pub struct VmContext {
1615
lexer: Lexer,
1716
module_name: ModuleName,
17+
package: ModuleName,
1818
path_str: String,
1919
vm: VirtualMachine,
2020
}
@@ -23,12 +23,19 @@ impl VmContext {
2323
pub fn new(text: Text, origin: ModuleOrigin) -> Self {
2424
let state = Container::new(MemphisState::init(origin.clone()));
2525
let runtime = Container::new(Runtime::new());
26-
Self::from_state(ModuleName::main(), text, origin, state, runtime)
26+
Self::from_state(
27+
ModuleName::main(),
28+
ModuleName::empty(),
29+
text,
30+
origin,
31+
state,
32+
runtime,
33+
)
2734
}
2835

29-
/// Initialize a context from a [`Source`] and existing treewalk state.
3036
pub fn from_state(
3137
module_name: ModuleName,
38+
package: ModuleName,
3239
text: Text,
3340
origin: ModuleOrigin,
3441
state: Container<MemphisState>,
@@ -37,16 +44,17 @@ impl VmContext {
3744
Self {
3845
lexer: Lexer::new(&text),
3946
module_name,
47+
package,
4048
path_str: origin.path_str(),
4149
vm: VirtualMachine::new(state, runtime),
4250
}
4351
}
4452

4553
pub fn run_inner(&mut self) -> VmResult<VmValue> {
46-
// TODO use a real syntax error here
47-
let code = self
48-
.compile()
49-
.map_err(|_e| self.vm.raise(Exception::syntax_error()))?;
54+
let code = self.compile().map_err(|e| {
55+
let exc = e.into_exception(&mut self.vm);
56+
self.vm.raise(exc)
57+
})?;
5058
self.vm.execute(code)
5159
}
5260

@@ -57,7 +65,7 @@ impl VmContext {
5765
.map_err(|e| CompilerError::SyntaxError(e.to_string()))?;
5866
ast.rewrite_last_expr_to_return();
5967

60-
let mut compiler = Compiler::new(&self.module_name, &self.path_str);
68+
let mut compiler = Compiler::new(&self.module_name, &self.package, &self.path_str);
6169
compiler.compile(&ast)
6270
}
6371

@@ -75,10 +83,15 @@ impl VmContext {
7583
}
7684

7785
#[cfg(test)]
78-
pub fn set_module_name(&mut self, name: ModuleName) {
86+
pub fn set_module(&mut self, name: ModuleName) {
7987
self.module_name = name;
8088
}
8189

90+
#[cfg(test)]
91+
pub fn set_pkg(&mut self, name: ModuleName) {
92+
self.package = name;
93+
}
94+
8295
#[cfg(any(test, feature = "wasm"))]
8396
pub fn from_text(text: Text) -> Self {
8497
Self::new(text, ModuleOrigin::Stdin)

src/bytecode_vm/interpreter.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,6 +1283,12 @@ b = f.bar()
12831283
assert_read_eq!(ctx, "x", int!(2));
12841284
}
12851285

1286+
#[test]
1287+
fn relative_import_from_package() {
1288+
let ctx = run_path("src/fixtures/imports/pkg_test/test_app.py");
1289+
assert_read_eq!(ctx, "a", int!(111));
1290+
}
1291+
12861292
#[test]
12871293
fn regular_import_error() {
12881294
let text = r#"

src/bytecode_vm/runtime/modules/asyncio.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ fn expect_float_or_raise(vm: &mut VirtualMachine, value: &VmValue) -> VmResult<f
4848
match value.as_float() {
4949
Some(i) => Ok(i),
5050
None => {
51-
let msg = VmValue::String("Expected a float".to_string());
52-
Exception::type_error(vm.heapify(msg)).raise(vm)
51+
let msg = vm.intern_string("Expected a float");
52+
Exception::type_error(msg).raise(vm)
5353
}
5454
}
5555
}
@@ -61,8 +61,8 @@ fn expect_coroutine_or_raise(
6161
match value.as_coroutine() {
6262
Some(i) => Ok(i.clone()),
6363
None => {
64-
let msg = VmValue::String("Expected a coroutine".to_string());
65-
Exception::type_error(vm.heapify(msg)).raise(vm)
64+
let msg = vm.intern_string("Expected a coroutine");
65+
Exception::type_error(msg).raise(vm)
6666
}
6767
}
6868
}

0 commit comments

Comments
 (0)