Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add and check the k code list to the entry. #642

Merged
merged 2 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion kclvm/config/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
//! The real path of `${my_pkg:KCL_MOD}/xxx/main.k` is `/usr/my_pkg/sub/main.k`.
use anyhow::Result;
use pcre2::bytes::Regex;
use std::path::PathBuf;
use std::path::{Path, PathBuf};

use crate::modfile::KCL_FILE_SUFFIX;

#[derive(Clone, Debug, Default)]
/// [`ModRelativePath`] is a path that is relative to the root package path.
Expand Down Expand Up @@ -144,6 +146,21 @@ impl ModRelativePath {
},
))
}

/// [`is_dir`] returns true if the path is a directory.
///
/// # Examples
///
/// ```rust
/// use kclvm_config::path::ModRelativePath;
/// let path = ModRelativePath::new("${name:KCL_MOD}/src/path".to_string());
/// assert_eq!(path.is_dir(), true);
/// let path = ModRelativePath::new("${name:KCL_MOD}/src/path/main.k".to_string());
/// assert_eq!(path.is_dir(), false);
/// ```
pub fn is_dir(&self) -> bool {
Path::new(&self.path).is_dir() || !self.path.ends_with(KCL_FILE_SUFFIX)
}
}

#[cfg(test)]
Expand Down
65 changes: 48 additions & 17 deletions kclvm/parser/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pub struct Entry {
name: String,
path: String,
k_files: Vec<String>,
k_code_lists: Vec<Option<String>>,
}

impl Entry {
Expand All @@ -126,6 +127,7 @@ impl Entry {
name,
path,
k_files: vec![],
k_code_lists: vec![],
}
}

Expand All @@ -149,10 +151,32 @@ impl Entry {
self.k_files.extend(k_files);
}

/// [`extend_k_files_and_codes`] will extend the k files and k codes of [`Entry`] to the given k file and k code.
pub fn extend_k_files_and_codes(
&mut self,
k_files: Vec<String>,
k_codes: &mut VecDeque<String>,
) {
for k_file in k_files.iter() {
self.k_code_lists.push(k_codes.pop_front());
self.k_files.push(k_file.to_string());
}
}

/// [`push_k_code`] will push the k code of [`Entry`] to the given k code.
pub fn push_k_code(&mut self, k_code: Option<String>) {
self.k_code_lists.push(k_code);
}

/// [`get_k_files`] will return the k files of [`Entry`].
pub fn get_k_files(&self) -> &Vec<String> {
&self.k_files
}

/// [`get_k_codes`] will return the k codes of [`Entry`].
pub fn get_k_codes(&self) -> &Vec<Option<String>> {
&self.k_code_lists
}
}

/// [`get_compile_entries_from_paths`] returns all the [`Entries`] for compilation from the given [`file_paths`].
Expand Down Expand Up @@ -251,8 +275,14 @@ pub fn get_compile_entries_from_paths(
return Err("No input KCL files or paths".to_string());
}
let mut result = Entries::default();
for s in file_paths {
let mut k_code_queue = VecDeque::from(opts.k_code_list.clone());
for (i, s) in file_paths.iter().enumerate() {
let path = ModRelativePath::from(s.to_string());

if path.is_dir() && opts.k_code_list.len() > i {
return Err("Invalid code list".to_string());
}

// If the path is a [`ModRelativePath`] with preffix '${<package_name>:KCL_MOD}',
// calculate the real path and the package name.
if let Some((pkg_name, pkg_path)) = path
Expand All @@ -269,8 +299,11 @@ pub fn get_compile_entries_from_paths(
.canonicalize_by_root_path(pkg_path)
.map_err(|err| err.to_string())?;
if let Some(root) = get_pkg_root(&s) {
let mut entry = Entry::new(pkg_name.clone(), root.clone());
entry.extend_k_files(get_main_files_from_pkg_path(&s, &root, &pkg_name, opts)?);
let mut entry: Entry = Entry::new(pkg_name.clone(), root.clone());
entry.extend_k_files_and_codes(
get_main_files_from_pkg_path(&s, &root, &pkg_name, opts)?,
&mut k_code_queue,
);
result.push_entry(entry);
continue;
}
Expand All @@ -282,17 +315,17 @@ pub fn get_compile_entries_from_paths(
.is_none()
{
// Push it into `result`, and deal it later.
result.push(kclvm_ast::MAIN_PKG.to_string(), path.get_path());
let mut entry = Entry::new(kclvm_ast::MAIN_PKG.to_string(), path.get_path());
entry.push_k_code(k_code_queue.pop_front());
result.push_entry(entry);
continue;
} else if let Some(root) = get_pkg_root(s) {
// If the path is a normal path.
let mut entry: Entry = Entry::new(kclvm_ast::MAIN_PKG.to_string(), root.clone());
entry.extend_k_files(get_main_files_from_pkg_path(
&s,
&root,
&kclvm_ast::MAIN_PKG.to_string(),
opts,
)?);
entry.extend_k_files_and_codes(
get_main_files_from_pkg_path(&s, &root, &kclvm_ast::MAIN_PKG.to_string(), opts)?,
&mut k_code_queue,
);
result.push_entry(entry);
}
}
Expand All @@ -304,12 +337,10 @@ pub fn get_compile_entries_from_paths(
{
let mut entry = Entry::new(kclvm_ast::MAIN_PKG.to_string(), "".to_string());
for s in file_paths {
entry.extend_k_files(get_main_files_from_pkg_path(
s,
"",
&kclvm_ast::MAIN_PKG.to_string(),
opts,
)?);
entry.extend_k_files_and_codes(
get_main_files_from_pkg_path(s, "", &kclvm_ast::MAIN_PKG.to_string(), opts)?,
&mut k_code_queue,
);
}
result.push_entry(entry);
}
Expand Down Expand Up @@ -432,7 +463,7 @@ fn get_main_files_from_pkg_path(
}

/// Get file list in the directory.
fn get_dir_files(dir: &str) -> Result<Vec<String>, String> {
pub fn get_dir_files(dir: &str) -> Result<Vec<String>, String> {
if !std::path::Path::new(dir).exists() {
return Ok(Vec::new());
}
Expand Down
19 changes: 6 additions & 13 deletions kclvm/parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,22 +290,15 @@ impl Loader {
// Get files from options with root.
// let k_files = self.get_main_files_from_pkg(entry.path(), entry.name())?;
let k_files = entry.get_k_files();
let maybe_k_codes = entry.get_k_codes();

// load module

for (i, filename) in k_files.iter().enumerate() {
if i < self.opts.k_code_list.len() {
let mut m = parse_file_with_session(
self.sess.clone(),
filename,
Some(self.opts.k_code_list[i].clone()),
)?;
self.fix_rel_import_path(entry.path(), &mut m);
pkg_files.push(m);
} else {
let mut m = parse_file_with_session(self.sess.clone(), filename, None)?;
self.fix_rel_import_path(entry.path(), &mut m);
pkg_files.push(m);
}
let mut m =
parse_file_with_session(self.sess.clone(), filename, maybe_k_codes[i].clone())?;
self.fix_rel_import_path(entry.path(), &mut m);
pkg_files.push(m);
}

// Insert an empty vec to determine whether there is a circular import.
Expand Down
1 change: 1 addition & 0 deletions kclvm/parser/src/testdata/test_k_code_list/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test = "test"
1 change: 1 addition & 0 deletions kclvm/parser/src/testdata/test_k_code_list/main1.k
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test1 = "test1"
17 changes: 17 additions & 0 deletions kclvm/parser/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,3 +497,20 @@ fn test_get_compile_entries_from_paths() {
kcl1_path.canonicalize().unwrap().to_str().unwrap()
);
}

#[test]
fn test_dir_with_k_code_list() {
let sm = SourceMap::new(FilePathMapping::empty());
let sess = Arc::new(ParseSession::with_source_map(Arc::new(sm)));
let testpath = PathBuf::from("./src/testdata/test_k_code_list")
.canonicalize()
.unwrap();

let mut opts = LoadProgramOptions::default();
opts.k_code_list = vec!["test_code = 1".to_string()];

match load_program(sess.clone(), &[&testpath.display().to_string()], Some(opts)) {
Ok(_) => panic!("unreachable code"),
Err(err) => assert_eq!(err, "Invalid code list"),
}
}
9 changes: 7 additions & 2 deletions kclvm/tools/src/LSP/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::env;
use std::path::PathBuf;
use std::process::Command;
use std::sync::Arc;

use indexmap::IndexSet;
use kclvm_ast::ast::Program;
Expand All @@ -17,6 +18,7 @@ use lsp_types::MarkedString;
use lsp_types::SymbolKind;
use lsp_types::Url;
use lsp_types::{Position, Range, TextDocumentContentChangeEvent};
use parking_lot::RwLock;

use crate::completion::KCLCompletionItem;
use crate::document_symbol::document_symbol;
Expand All @@ -35,8 +37,11 @@ fn compile_test_file(testfile: &str) -> (String, Program, ProgramScope, IndexSet

let file = test_file.to_str().unwrap().to_string();

let (program, prog_scope, diags) =
parse_param_and_compile(Param { file: file.clone() }, None).unwrap();
let (program, prog_scope, diags) = parse_param_and_compile(
Param { file: file.clone() },
Some(Arc::new(RwLock::new(Default::default()))),
)
.unwrap();
(file, program, prog_scope, diags)
}

Expand Down
25 changes: 20 additions & 5 deletions kclvm/tools/src/LSP/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::cell::RefCell;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::{fs, sync::Arc};

Expand All @@ -15,6 +15,7 @@ use kclvm_driver::kpm_metadata::fetch_metadata;
use kclvm_driver::{get_kcl_files, lookup_compile_unit};
use kclvm_error::Diagnostic;
use kclvm_error::Position as KCLPos;
use kclvm_parser::entry::get_dir_files;
use kclvm_parser::{load_program, ParseSession};
use kclvm_sema::resolver::scope::Scope;
use kclvm_sema::resolver::{resolve_program, scope::ProgramScope};
Expand Down Expand Up @@ -114,10 +115,24 @@ fn load_files_code_from_vfs(files: &[&str], vfs: Arc<RwLock<Vfs>>) -> anyhow::Re
}
None => {
// In order to ensure that k_file corresponds to k_code, load the code from the file system if not exist
res.push(
fs::read_to_string(path)
.map_err(|_| anyhow::anyhow!("can't convert file to url: {}", file))?,
);
let p: &Path = path.as_ref();
if p.is_file() {
res.push(
fs::read_to_string(path)
.map_err(|_| anyhow::anyhow!("can't convert file to url: {}", file))?,
);
} else if p.is_dir() {
let k_files = get_dir_files(p.to_str().unwrap())
.map_err(|_| anyhow::anyhow!("can't get dir files: {} ", file))?;
for k_file in k_files {
let k_file_path = Path::new(k_file.as_str());
res.push(
fs::read_to_string(k_file_path).map_err(|_| {
anyhow::anyhow!("can't convert file to url: {}", file)
})?,
);
}
}
}
}
}
Expand Down
Loading