From 0d34de4f29990d9f5922b66bb31e9ecb33c58823 Mon Sep 17 00:00:00 2001 From: He1pa <56333845+He1pa@users.noreply.github.com> Date: Thu, 14 Nov 2024 22:22:46 +0800 Subject: [PATCH] feat: add api to get all schema under path (#1754) feat: add new api to get all schema under path Signed-off-by: he1pa <18012015693@163.com> --- kclvm/api/src/service/service_impl.rs | 2 +- kclvm/parser/src/tests.rs | 6 +- kclvm/query/src/query.rs | 104 +++++++++++++++++- .../get_schema_ty_under_path/aaa/kcl.mod | 8 ++ .../get_schema_ty_under_path/aaa/main.k | 5 + .../get_schema_ty_under_path/aaa/sub/sub.k | 3 + .../get_schema_ty_under_path/bbb/kcl.mod | 5 + .../get_schema_ty_under_path/bbb/main.k | 4 + .../helloworld_0.0.1/README.md | 2 + .../helloworld_0.0.1/kcl.mod | 5 + .../helloworld_0.0.1/main.k | 3 + kclvm/sema/src/resolver/mod.rs | 11 +- kclvm/sema/src/resolver/tests.rs | 2 +- 13 files changed, 146 insertions(+), 14 deletions(-) create mode 100644 kclvm/query/src/test_data/get_schema_ty_under_path/aaa/kcl.mod create mode 100644 kclvm/query/src/test_data/get_schema_ty_under_path/aaa/main.k create mode 100644 kclvm/query/src/test_data/get_schema_ty_under_path/aaa/sub/sub.k create mode 100644 kclvm/query/src/test_data/get_schema_ty_under_path/bbb/kcl.mod create mode 100644 kclvm/query/src/test_data/get_schema_ty_under_path/bbb/main.k create mode 100644 kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/README.md create mode 100644 kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/kcl.mod create mode 100644 kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/main.k diff --git a/kclvm/api/src/service/service_impl.rs b/kclvm/api/src/service/service_impl.rs index e402d6714..1d09d4807 100644 --- a/kclvm/api/src/service/service_impl.rs +++ b/kclvm/api/src/service/service_impl.rs @@ -649,7 +649,7 @@ impl KclvmServiceImpl { for (k, schema_ty) in get_full_schema_type( Some(&args.schema_name), CompilationOptions { - k_files: exec_args.clone().k_filename_list, + paths: exec_args.clone().k_filename_list, loader_opts: Some(exec_args.get_load_program_options()), resolve_opts: Options { resolve_val: true, diff --git a/kclvm/parser/src/tests.rs b/kclvm/parser/src/tests.rs index 572014adf..bcbe17b05 100644 --- a/kclvm/parser/src/tests.rs +++ b/kclvm/parser/src/tests.rs @@ -848,7 +848,7 @@ fn parse_all_file_under_path() { .join("testdata") .join("parse_all_modules"); - let main = testpath.join("a").join("main.k"); + let main = testpath.join("a"); let main = main.to_str().unwrap(); let helloworld = testpath.join("helloworld_0.0.1"); let b = testpath.join("b"); @@ -865,6 +865,6 @@ fn parse_all_file_under_path() { let res = load_all_files_under_paths(sess.clone(), &[main], Some(opt), None).unwrap(); - assert_eq!(res.program.pkgs.keys().len(), 3); - assert_eq!(res.paths.len(), 3); + assert_eq!(res.program.pkgs.keys().len(), 4); + assert_eq!(res.paths.len(), 4); } diff --git a/kclvm/query/src/query.rs b/kclvm/query/src/query.rs index 6646ac980..f7f926cee 100644 --- a/kclvm/query/src/query.rs +++ b/kclvm/query/src/query.rs @@ -2,9 +2,13 @@ use std::{cell::RefCell, rc::Rc, sync::Arc}; use anyhow::Result; use indexmap::IndexMap; -use kclvm_parser::{load_program, LoadProgramOptions, ParseSession}; +use kclvm_parser::{load_all_files_under_paths, load_program, LoadProgramOptions, ParseSession}; use kclvm_sema::{ - resolver::{resolve_program_with_opts, scope::Scope, Options}, + resolver::{ + resolve_program_with_opts, + scope::{ProgramScope, Scope}, + Options, + }, ty::SchemaType, }; @@ -82,7 +86,7 @@ pub fn get_schema_type( ) -> Result> { let mut result = IndexMap::new(); let scope = resolve_file(&CompilationOptions { - k_files: vec![file.to_string()], + paths: vec![file.to_string()], loader_opts: code.map(|c| LoadProgramOptions { k_code_list: vec![c.to_string()], ..Default::default() @@ -119,7 +123,7 @@ pub fn get_schema_type( #[derive(Debug, Clone, Default)] pub struct CompilationOptions { - pub k_files: Vec, + pub paths: Vec, pub loader_opts: Option, pub resolve_opts: Options, pub get_schema_opts: GetSchemaOption, @@ -141,7 +145,7 @@ pub struct CompilationOptions { /// let result = get_full_schema_type( /// Some("a"), /// CompilationOptions { -/// k_files: vec![ +/// paths: vec![ /// work_dir_parent.join("aaa").join("main.k").canonicalize().unwrap().display().to_string() /// ], /// loader_opts: Some(LoadProgramOptions { @@ -189,6 +193,78 @@ pub fn get_full_schema_type( Ok(result) } +/// Service for getting the full schema type list under paths. +/// Different from `get_full_schema_type`, this function will compile files that are not imported +/// And key of result is pka name, not schema name. +/// +/// # Examples +/// +/// ``` +/// use kclvm_parser::LoadProgramOptions; +/// use kclvm_query::query::CompilationOptions; +/// use kclvm_query::query::get_full_schema_type_under_path; +/// use std::path::Path; +/// use maplit::hashmap; +/// use kclvm_ast::MAIN_PKG; +/// +/// let work_dir_parent = Path::new(".").join("src").join("test_data").join("get_schema_ty_under_path"); +/// +/// let result = get_full_schema_type_under_path( +/// None, +/// CompilationOptions { +/// paths: vec![ +/// work_dir_parent.join("aaa").canonicalize().unwrap().display().to_string() +/// ], +/// loader_opts: Some(LoadProgramOptions { +/// work_dir: work_dir_parent.join("aaa").canonicalize().unwrap().display().to_string(), +/// package_maps: hashmap!{ +/// "bbb".to_string() => work_dir_parent.join("bbb").canonicalize().unwrap().display().to_string(), +/// "helloworld".to_string() => work_dir_parent.join("helloworld_0.0.1").canonicalize().unwrap().display().to_string(), +/// }, +/// ..Default::default() +/// }), +/// ..Default::default() +/// } +/// ).unwrap(); +/// assert_eq!(result.len(), 4); +/// assert_eq!(result.get(MAIN_PKG).unwrap().len(), 1); +/// assert_eq!(result.get("bbb").unwrap().len(), 2); +/// assert_eq!(result.get("helloworld").unwrap().len(), 1); +/// assert_eq!(result.get("sub").unwrap().len(), 1); +/// ``` +pub fn get_full_schema_type_under_path( + schema_name: Option<&str>, + opts: CompilationOptions, +) -> Result>> { + let mut result = IndexMap::new(); + let program_scope = resolve_paths(&opts)?; + for (pkg, scope) in &program_scope.scope_map { + for (name, o) in &scope.borrow().elems { + if o.borrow().ty.is_schema() { + let schema_ty = o.borrow().ty.into_schema_type(); + if opts.get_schema_opts == GetSchemaOption::All + || (opts.get_schema_opts == GetSchemaOption::Definitions + && !schema_ty.is_instance) + || (opts.get_schema_opts == GetSchemaOption::Instances && schema_ty.is_instance) + { + // Schema name filter + match schema_name { + Some(schema_name) => { + if schema_name.is_empty() || schema_name == name { + result.entry(pkg.clone()).or_insert(vec![]).push(schema_ty); + } + } + None => { + result.entry(pkg.clone()).or_insert(vec![]).push(schema_ty); + } + } + } + } + } + } + Ok(result) +} + fn get_full_schema_type_recursive(schema_ty: SchemaType) -> Result { let mut result = schema_ty; if let Some(base) = result.base { @@ -201,7 +277,7 @@ fn resolve_file(opts: &CompilationOptions) -> Result>> { let sess = Arc::new(ParseSession::default()); let mut program = match load_program( sess, - &opts.k_files.iter().map(AsRef::as_ref).collect::>(), + &opts.paths.iter().map(AsRef::as_ref).collect::>(), opts.loader_opts.clone(), None, ) { @@ -216,3 +292,19 @@ fn resolve_file(opts: &CompilationOptions) -> Result>> { None => Err(anyhow::anyhow!("main scope is not found")), } } + +fn resolve_paths(opts: &CompilationOptions) -> Result { + let sess = Arc::new(ParseSession::default()); + let mut program = load_all_files_under_paths( + sess, + &opts.paths.iter().map(AsRef::as_ref).collect::>(), + opts.loader_opts.clone(), + None, + )? + .program; + Ok(resolve_program_with_opts( + &mut program, + opts.resolve_opts.clone(), + None, + )) +} diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/kcl.mod b/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/kcl.mod new file mode 100644 index 000000000..062218adb --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/kcl.mod @@ -0,0 +1,8 @@ +[package] +name = "aaa" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +bbb = { path = "../bbb" } +helloworld = "0.0.1" \ No newline at end of file diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/main.k b/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/main.k new file mode 100644 index 000000000..5c48776d5 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/main.k @@ -0,0 +1,5 @@ +import bbb + +a = bbb.B { + name: "b instance in a" +} \ No newline at end of file diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/sub/sub.k b/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/sub/sub.k new file mode 100644 index 000000000..8000c5ff0 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/aaa/sub/sub.k @@ -0,0 +1,3 @@ +schema Sub: + name: str + \ No newline at end of file diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/bbb/kcl.mod b/kclvm/query/src/test_data/get_schema_ty_under_path/bbb/kcl.mod new file mode 100644 index 000000000..e9ea10a52 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/bbb/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "bbb" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/bbb/main.k b/kclvm/query/src/test_data/get_schema_ty_under_path/bbb/main.k new file mode 100644 index 000000000..15b434862 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/bbb/main.k @@ -0,0 +1,4 @@ +schema Base: + n: str +schema B(Base): + name: str \ No newline at end of file diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/README.md b/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/README.md new file mode 100644 index 000000000..4d63fef38 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/README.md @@ -0,0 +1,2 @@ +## Introduction +This is a kcl package named helloworld. diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/kcl.mod b/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/kcl.mod new file mode 100644 index 000000000..bef7e7f76 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "helloworld" +edition = "0.0.1" +version = "0.0.1" + diff --git a/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/main.k b/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/main.k new file mode 100644 index 000000000..571977787 --- /dev/null +++ b/kclvm/query/src/test_data/get_schema_ty_under_path/helloworld_0.0.1/main.k @@ -0,0 +1,3 @@ +The_first_kcl_program = 'Hello World!' +schema Hello: + name: str \ No newline at end of file diff --git a/kclvm/sema/src/resolver/mod.rs b/kclvm/sema/src/resolver/mod.rs index 6834d7137..8b318c993 100644 --- a/kclvm/sema/src/resolver/mod.rs +++ b/kclvm/sema/src/resolver/mod.rs @@ -97,8 +97,13 @@ impl<'ctx> Resolver<'ctx> { } } - pub(crate) fn check_and_lint(&mut self, pkgpath: &str) -> ProgramScope { - self.check(pkgpath); + pub(crate) fn check_and_lint_all_pkgs(&mut self) -> ProgramScope { + self.check(kclvm_ast::MAIN_PKG); + for pkg in self.program.pkgs.keys() { + if !self.scope_map.contains_key(pkg) { + self.check(pkg); + } + } let mut scope_map = self.scope_map.clone(); for invalid_pkg_scope in &self.ctx.invalid_pkg_scope { scope_map.remove(invalid_pkg_scope); @@ -205,7 +210,7 @@ pub fn resolve_program_with_opts( } } } - let scope = resolver.check_and_lint(kclvm_ast::MAIN_PKG); + let scope = resolver.check_and_lint_all_pkgs(); if let Some(cached_scope) = cached_scope.as_ref() { if let Some(mut cached_scope) = cached_scope.try_write() { diff --git a/kclvm/sema/src/resolver/tests.rs b/kclvm/sema/src/resolver/tests.rs index 1024b86c9..3d0240973 100644 --- a/kclvm/sema/src/resolver/tests.rs +++ b/kclvm/sema/src/resolver/tests.rs @@ -397,7 +397,7 @@ fn test_lint() { pre_process_program(&mut program, &opts); let mut resolver = Resolver::new(&program, opts); resolver.resolve_import(); - resolver.check_and_lint(kclvm_ast::MAIN_PKG); + resolver.check_and_lint_all_pkgs(); let root = &program.root.clone(); let filename = Path::new(&root.clone())