diff --git a/src/compiler.rs b/src/compiler.rs index 744e46f..1e85734 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -795,6 +795,28 @@ impl StmtVisitor for Compiler<'_> { let line = stmt_line_number(stmt); + // allocate names - local or global + let nil_constant = self.insert_constant(Nil::create())?; + for what in &stmt.what { + if self.is_global_scope() { + self.insert_global(&what.text)?; + } else { + self.emit((what.line, what.line), Op::PushConstant(nil_constant)); + self.insert_local(what.text.to_string())?; + } + } + if stmt.what.is_empty() && stmt.module.kind == TokenKind::Name { + if self.is_global_scope() { + self.insert_global(&stmt.module.text)?; + } else { + self.emit( + (stmt.module.line, stmt.module.line), + Op::PushConstant(nil_constant), + ); + self.insert_local(stmt.module.text.to_string())?; + } + } + // resolve filename and get full filepath let path = match stmt.module.kind { TokenKind::Name => self @@ -831,12 +853,12 @@ impl StmtVisitor for Compiler<'_> { }; let module_constant = self.insert_constant(upcast_obj(module.clone()))?; - self.emit(stmt_line_number(stmt), Op::PushConstant(module_constant)); + // evaluate module + self.emit(line, Op::PushConstant(module_constant)); + self.emit(line, Op::EvalModule); if stmt.what.is_empty() { - // evaluate the module, and then assign the resulting object to the module name as - // appropriate - self.emit(line, Op::EnterModule); + // assign the resulting object to the module name as appropriate // only assign if it's a name, if it's a string we don't assign anything if stmt.module.kind == TokenKind::Name { self.emit_assign(line, &stmt.module.text)?; @@ -845,8 +867,16 @@ impl StmtVisitor for Compiler<'_> { } } else { // evaluate the module, and then assign all names that were imported as appropriate - // TODO Compiler::visit_import_stmt - visit names from module - todo!("import names from module") + for what in stmt.what.iter() { + self.emit(line, Op::Dup); + let constant_id = self.insert_constant(Str::create(&what.text))?; + self.emit(line, Op::GetAttr(constant_id)); + self.emit_assign(line, &what.text)?; + } + + // not importing the module name itself, so clean up the stack after we're done setting + // names + self.emit(line, Op::Pop); } Ok(()) diff --git a/src/disassemble.rs b/src/disassemble.rs index ab60232..93a39e5 100644 --- a/src/disassemble.rs +++ b/src/disassemble.rs @@ -37,6 +37,11 @@ fn disassemble_chunk(chunk: &Chunk, globals: &Vec, constants: &Vec arg = format!("{}", &constants[*constant_id as usize].borrow()); info = format!("(constant ID {constant_id})"); } + Op::Dup => { + op_str = "DUP"; + arg = String::new(); + info = String::new(); + } Op::GetLocal(local_id) => { op_str = "GET_LOCAL"; let local = &chunk.locals[*local_id as usize]; @@ -109,8 +114,8 @@ fn disassemble_chunk(chunk: &Chunk, globals: &Vec, constants: &Vec arg = String::new(); info = String::new(); } - Op::EnterModule => { - op_str = "ENTER_MODULE"; + Op::EvalModule => { + op_str = "EVAL_MODULE"; arg = String::new(); info = String::new(); } diff --git a/src/vm.rs b/src/vm.rs index c8dfff7..a9ffbda 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -8,6 +8,7 @@ pub enum Op { // Stack functions Pop, PushConstant(LongOpArg), + Dup, // Variables GetLocal(LocalIndex), @@ -34,7 +35,7 @@ pub enum Op { // VM control Nop, - EnterModule, + EvalModule, ExitModule, } @@ -155,10 +156,9 @@ impl<'c> Vm<'c> { /// Gets the chunk of the currently executing frame. pub fn chunk(&self) -> Option<&Chunk> { - if let Function::Chunk(chunk) = &self.frame().function { - Some(chunk) - } else { - None + match &self.frame().function { + Function::Chunk(chunk) | Function::Module(chunk) => Some(chunk), + Function::Builtin(_, _) => None, } } @@ -339,6 +339,10 @@ impl<'c> Vm<'c> { let constant = self.constants[constant_id as usize].clone(); self.push(constant); } + Op::Dup => { + let top = self.peek(); + self.push(top); + } Op::GetLocal(local_index) => { let local = &self.chunk().expect("no chunk").locals[local_index as usize]; let value = self.stack[self.frame().stack_base + local.slot as usize].clone(); @@ -470,7 +474,7 @@ impl<'c> Vm<'c> { Op::Nop => { continue; } - Op::EnterModule => { + Op::EvalModule => { // check if the module has been evaluated yet let module = self.peek(); let value = with_obj_downcast(module.clone(), |module: &Module| { diff --git a/tests/modules.npp b/tests/modules.npp index e202c61..4e22299 100644 --- a/tests/modules.npp +++ b/tests/modules.npp @@ -4,3 +4,9 @@ import test_import_local println(test_import_local.foo) println(test_import_local.bar) println(test_import_local.baz) + +import foo, bar, baz from test_import_local + +println(foo) +println(bar) +println(baz) diff --git a/tests/modules.npp.expect b/tests/modules.npp.expect index b8de9d0..2fab882 100644 --- a/tests/modules.npp.expect +++ b/tests/modules.npp.expect @@ -3,3 +3,6 @@ importing test_import_local 1 2 3 +1 +2 +3