diff --git a/.github/workflows/ubuntu_test.yaml b/.github/workflows/ubuntu_test.yaml index aadc775f5..251cf4818 100644 --- a/.github/workflows/ubuntu_test.yaml +++ b/.github/workflows/ubuntu_test.yaml @@ -56,7 +56,7 @@ jobs: uses: coverallsapp/github-action@master with: github-token: ${{ secrets.GITHUB_TOKEN }} - path-to-lcov: ./kclvm/.kclvm/lcov.info + path-to-lcov: ./kclvm/.kclvm_cov/lcov.info - uses: actions/upload-artifact@v3 with: diff --git a/.gitignore b/.gitignore index 29d5ee571..9595591e4 100644 --- a/.gitignore +++ b/.gitignore @@ -77,6 +77,7 @@ lark_parser.pickle # KCLVM cache and temp output .kclvm +.kclvm_cov *.dylib *.so *.dll diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_11/kcl.mod new file mode 100644 index 000000000..a626cfb0f --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_11" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/model/main.k b/kclvm/cmd/src/test_data/instances/test_inst_11/model/main.k new file mode 100644 index 000000000..b43778076 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/model/main.k @@ -0,0 +1,3 @@ +schema K11: + msg: str + \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/sub/main.k b/kclvm/cmd/src/test_data/instances/test_inst_11/sub/main.k new file mode 100644 index 000000000..486e93f97 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/sub/main.k @@ -0,0 +1,5 @@ +import model as m + +k11_inst: m.K11 { + msg: "k11_in_sub" +} \ No newline at end of file diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/expected b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/expected new file mode 100644 index 000000000..3ad7b524b --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/expected @@ -0,0 +1,2 @@ +k11_inst: + msg: k11_in_main diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/kcl.mod b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/kcl.mod new file mode 100644 index 000000000..5c0234dc8 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "test_inst_111" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/kcl.yaml b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/kcl.yaml new file mode 100644 index 000000000..553e82d00 --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/kcl.yaml @@ -0,0 +1,6 @@ +kcl_cli_configs: + file: + - ../sub/main.k + - ./main.k + package_maps: + test_inst_11: ./src/test_data/instances/test_inst_11 diff --git a/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/main.k b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/main.k new file mode 100644 index 000000000..c6985755e --- /dev/null +++ b/kclvm/cmd/src/test_data/instances/test_inst_11/test_inst_111/main.k @@ -0,0 +1,5 @@ +import test_inst_11.model as m + +k11_inst: m.K11 { + msg= "k11_in_main" +} \ No newline at end of file diff --git a/kclvm/cmd/src/tests.rs b/kclvm/cmd/src/tests.rs index 9fc2558ca..5d4ba5423 100644 --- a/kclvm/cmd/src/tests.rs +++ b/kclvm/cmd/src/tests.rs @@ -472,6 +472,7 @@ fn test_instances_with_yaml() { "test_inst_8", "test_inst_9", "test_inst_10", + "test_inst_11/test_inst_111", ]; for case in &test_cases { diff --git a/kclvm/config/src/modfile.rs b/kclvm/config/src/modfile.rs index 0abe5c010..f5f27b73d 100644 --- a/kclvm/config/src/modfile.rs +++ b/kclvm/config/src/modfile.rs @@ -84,7 +84,7 @@ pub struct KCLModFileExpectedSection { pub global_version: Option, } -pub fn get_pkg_root_from_paths(file_paths: &[String]) -> Result { +pub fn get_pkg_root_from_paths(file_paths: &[String], workdir: String) -> Result { if file_paths.is_empty() { return Err("No input KCL files or paths".to_string()); } @@ -107,6 +107,8 @@ pub fn get_pkg_root_from_paths(file_paths: &[String]) -> Result } if m.len() == 1 { return Ok(last_root); + } else if !workdir.is_empty() { + return Ok(workdir); } Err(format!("conflict kcl.mod file paths: {:?}", m)) @@ -162,17 +164,17 @@ mod modfile_test { #[test] fn test_get_pkg_root_from_paths() { assert_eq!( - get_pkg_root_from_paths(&[]), + get_pkg_root_from_paths(&[], "".to_string()), Err("No input KCL files or paths".to_string()) ); assert_eq!( - get_pkg_root_from_paths(&["wrong_path".to_string()]), + get_pkg_root_from_paths(&["wrong_path".to_string()], "".to_string()), Ok("".to_string()) ); let expected_root = std::path::Path::new(TEST_ROOT).canonicalize().unwrap(); let expected = expected_root.adjust_canonicalization(); assert_eq!( - get_pkg_root_from_paths(&[SETTINGS_FILE.to_string()]), + get_pkg_root_from_paths(&[SETTINGS_FILE.to_string()], "".to_string()), Ok(expected.to_string()) ); } diff --git a/kclvm/driver/src/lib.rs b/kclvm/driver/src/lib.rs index f5314ab2e..6acab4029 100644 --- a/kclvm/driver/src/lib.rs +++ b/kclvm/driver/src/lib.rs @@ -77,7 +77,7 @@ pub fn canonicalize_input_files( } // Get the root path of the project - let pkgroot = kclvm_config::modfile::get_pkg_root_from_paths(&kcl_paths)?; + let pkgroot = kclvm_config::modfile::get_pkg_root_from_paths(&kcl_paths, work_dir)?; // The second traversal replaces ${KCL_MOD} with the project root path kcl_paths = kcl_paths diff --git a/kclvm/makefile b/kclvm/makefile index 2e6754e4f..ee29d3e48 100644 --- a/kclvm/makefile +++ b/kclvm/makefile @@ -67,8 +67,9 @@ codecov: codecov-lcov: rustup component add llvm-tools-preview cargo install cargo-llvm-cov - mkdir $(PWD)/.kclvm - cargo llvm-cov --lcov --output-path $(PWD)/.kclvm/lcov.info --workspace --ignore-filename-regex gpyrpc.rs -- --nocapture + rm -rf $(PWD)/.kclvm_cov + mkdir $(PWD)/.kclvm_cov + cargo llvm-cov --lcov --output-path $(PWD)/.kclvm_cov/lcov.info --workspace --ignore-filename-regex gpyrpc.rs -- --nocapture # Test runtime libaries using python functions test-runtime: install-kclvm-py install-pytest diff --git a/kclvm/parser/src/entry.rs b/kclvm/parser/src/entry.rs index 71c2bd980..a49f3d415 100644 --- a/kclvm/parser/src/entry.rs +++ b/kclvm/parser/src/entry.rs @@ -15,6 +15,7 @@ use crate::LoadProgramOptions; /// The reason why the [`Entries`] is not an [`IndexMap`] is that the [`entries`] is duplicable and ordered. #[derive(Default, Debug)] pub struct Entries { + root_path: String, entries: VecDeque, } @@ -109,6 +110,11 @@ impl Entries { self.entries.iter_mut().try_for_each(f)?; return Ok(()); } + + /// [`get_root_path`] will return the root path of [`Entries`]. + pub fn get_root_path(&self) -> &String { + &self.root_path + } } /// [`Entry`] is a package name and package root path pair. @@ -345,50 +351,54 @@ pub fn get_compile_entries_from_paths( result.push_entry(entry); } - // The main 'kcl.mod' path can be found only once. - // Replace all the '${KCL_MOD}' with the real path of main 'kcl.mod'. - if result + let pkg_root = if result .get_unique_normal_paths_by_name(kclvm_ast::MAIN_PKG) .len() == 1 + && opts.work_dir.is_empty() { - // If the [`ModRelativePath`] with preffix '${KCL_MOD}'. - // Replace the '${KCL_MOD}' by the root path of package '__main__'. - - // Calculate the root path of package '__main__'. - let pkg_root; - let main_entry = result - .get_nth_entry_by_name(0, kclvm_ast::MAIN_PKG) - .ok_or_else(|| format!("program entry not found in {:?}", file_paths))?; - pkg_root = main_entry.path().to_string(); - - // Replace the '${KCL_MOD}' of all the paths with package name '__main__'. - result.apply_to_all_entries(|entry| { - let path = ModRelativePath::from(entry.path().to_string()); - if entry.name() == kclvm_ast::MAIN_PKG - && path.is_relative_path().map_err(|err| err.to_string())? - { - entry.set_path(pkg_root.to_string()); - entry.extend_k_files(get_main_files_from_pkg_path( - &path - .canonicalize_by_root_path(&pkg_root) - .map_err(|err| err.to_string())?, - &pkg_root, - &kclvm_ast::MAIN_PKG.to_string(), - opts, - )?); - } - return Ok(()); - })?; - return Ok(result); - } + // If the 'kcl.mod' can be found only once, the package root path will be the path of the 'kcl.mod'. + result + .get_unique_normal_paths_by_name(kclvm_ast::MAIN_PKG) + .get(0) + .unwrap() + .to_string() + } else if !opts.work_dir.is_empty() { + // If the 'kcl.mod' can be found more than once, the package root path will be the 'work_dir'. + if let Some(root_work_dir) = get_pkg_root(&opts.work_dir) { + root_work_dir + } else { + "".to_string() + } + } else { + // If there are more than one main 'kcl.mod' files, return error. + // the root path of package '__main__' can only one. + return Err(format!( + "conflict kcl.mod file paths: {:?}", + result.get_unique_normal_paths_by_name(kclvm_ast::MAIN_PKG) + )); + }; + result.root_path = pkg_root.clone(); + // Replace the '${KCL_MOD}' of all the paths with package name '__main__'. + result.apply_to_all_entries(|entry| { + let path = ModRelativePath::from(entry.path().to_string()); + if entry.name() == kclvm_ast::MAIN_PKG + && path.is_relative_path().map_err(|err| err.to_string())? + { + entry.set_path(pkg_root.to_string()); + entry.extend_k_files(get_main_files_from_pkg_path( + &path + .canonicalize_by_root_path(&pkg_root) + .map_err(|err| err.to_string())?, + &pkg_root, + &kclvm_ast::MAIN_PKG.to_string(), + opts, + )?); + } + return Ok(()); + })?; - // If there are more than one main 'kcl.mod' files, return error. - // the root path of package '__main__' can only one. - Err(format!( - "conflict kcl.mod file paths: {:?}", - result.get_unique_normal_paths_by_name(kclvm_ast::MAIN_PKG) - )) + return Ok(result); } /// Get files in the main package with the package root. diff --git a/kclvm/parser/src/lib.rs b/kclvm/parser/src/lib.rs index 70c7d1d50..0cd42ecb8 100644 --- a/kclvm/parser/src/lib.rs +++ b/kclvm/parser/src/lib.rs @@ -313,10 +313,7 @@ impl Loader { fn _load_main(&mut self) -> Result { let compile_entries = get_compile_entries_from_paths(&self.paths, &self.opts)?; let mut pkgs = HashMap::new(); - - let main_program_root = compile_entries - .contains_pkg_name(&kclvm_ast::MAIN_PKG.to_string()) - .ok_or(format!("main package not found in {:?}", &self.paths))?; + let workdir = compile_entries.get_root_path().to_string(); debug_assert_eq!(compile_entries.len(), self.paths.len()); @@ -349,7 +346,7 @@ impl Loader { // Insert the complete ast to replace the empty list. pkgs.insert(kclvm_ast::MAIN_PKG.to_string(), pkg_files); Ok(ast::Program { - root: main_program_root.path().to_string(), + root: workdir, main: kclvm_ast::MAIN_PKG.to_string(), pkgs, }) diff --git a/kclvm/tools/src/LSP/src/request.rs b/kclvm/tools/src/LSP/src/request.rs index 68319eb3b..f1a12d03a 100644 --- a/kclvm/tools/src/LSP/src/request.rs +++ b/kclvm/tools/src/LSP/src/request.rs @@ -1,5 +1,5 @@ +use anyhow::Ok; use crossbeam_channel::Sender; - use lsp_types::TextEdit; use ra_ap_vfs::VfsPath; use std::time::Instant;