From a240aead8c454957f727301a46cd9568b4839607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=BD=C3=A1dn=C3=ADk?= Date: Wed, 20 Oct 2021 00:23:59 +0300 Subject: [PATCH] Add loading module from file Currently, `use spam.nu` creates a module `spam`. Therefore, after the first `use`, it is possible to call both `use spam.nu` and `use spam` with the same effect. --- crates/nu-parser/src/parse_keywords.rs | 57 +++++++++++++++++++++----- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index e68bbc41de..beafb70544 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -1,5 +1,5 @@ use nu_protocol::{ - ast::{Block, Call, Expr, Expression, ImportPatternMember, Pipeline, Statement}, + ast::{Block, Call, Expr, Expression, ImportPattern, ImportPatternMember, Pipeline, Statement}, engine::StateWorkingSet, span, DeclId, Span, SyntaxShape, Type, }; @@ -349,8 +349,7 @@ pub fn parse_module_block( (stmt, err) } b"export" => { - let (stmt, err) = - parse_export(working_set, &pipeline.commands[0].parts); + let (stmt, err) = parse_export(working_set, &pipeline.commands[0].parts); if err.is_none() { let decl_name = @@ -499,14 +498,50 @@ pub fn parse_use( let (import_pattern, err) = parse_import_pattern(working_set, spans[1]); error = error.or(err); - let exports = if let Some(block_id) = working_set.find_module(&import_pattern.head) { - working_set.get_block(block_id).exports.clone() - } else { - return ( - garbage_statement(spans), - Some(ParseError::ModuleNotFound(spans[1])), - ); - }; + let (import_pattern, exports) = + if let Some(block_id) = working_set.find_module(&import_pattern.head) { + ( + import_pattern, + working_set.get_block(block_id).exports.clone(), + ) + } else { + // It could be a file + let module_filename = String::from_utf8_lossy(&import_pattern.head).to_string(); + let module_path = Path::new(&module_filename); + let module_name = if let Some(stem) = module_path.file_stem() { + stem.to_string_lossy().to_string() + } else { + return ( + garbage_statement(spans), + Some(ParseError::ModuleNotFound(spans[1])), + ); + }; + + if let Ok(contents) = std::fs::read(module_path) { + let span_start = working_set.next_span_start(); + working_set.add_file(module_filename, &contents); + let span_end = working_set.next_span_start(); + + let (block, err) = + parse_module_block(working_set, &[Span::new(span_start, span_end)]); + error = error.or(err); + + let block_id = working_set.add_module(&module_name, block); + + ( + ImportPattern { + head: module_name.into(), + members: import_pattern.members, + }, + working_set.get_block(block_id).exports.clone(), + ) + } else { + return ( + garbage_statement(spans), + Some(ParseError::ModuleNotFound(spans[1])), + ); + } + }; let exports = if import_pattern.members.is_empty() { exports