Skip to content

Commit

Permalink
feat: add api to get all schema under path (#1754)
Browse files Browse the repository at this point in the history
feat: add new api to get all schema under path

Signed-off-by: he1pa <18012015693@163.com>
  • Loading branch information
He1pa authored Nov 14, 2024
1 parent 62a3c2f commit 0d34de4
Show file tree
Hide file tree
Showing 13 changed files with 146 additions and 14 deletions.
2 changes: 1 addition & 1 deletion kclvm/api/src/service/service_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions kclvm/parser/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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);
}
104 changes: 98 additions & 6 deletions kclvm/query/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -82,7 +86,7 @@ pub fn get_schema_type(
) -> Result<IndexMap<String, SchemaType>> {
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()
Expand Down Expand Up @@ -119,7 +123,7 @@ pub fn get_schema_type(

#[derive(Debug, Clone, Default)]
pub struct CompilationOptions {
pub k_files: Vec<String>,
pub paths: Vec<String>,
pub loader_opts: Option<LoadProgramOptions>,
pub resolve_opts: Options,
pub get_schema_opts: GetSchemaOption,
Expand All @@ -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 {
Expand Down Expand Up @@ -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<IndexMap<String, Vec<SchemaType>>> {
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<SchemaType> {
let mut result = schema_ty;
if let Some(base) = result.base {
Expand All @@ -201,7 +277,7 @@ fn resolve_file(opts: &CompilationOptions) -> Result<Rc<RefCell<Scope>>> {
let sess = Arc::new(ParseSession::default());
let mut program = match load_program(
sess,
&opts.k_files.iter().map(AsRef::as_ref).collect::<Vec<_>>(),
&opts.paths.iter().map(AsRef::as_ref).collect::<Vec<_>>(),
opts.loader_opts.clone(),
None,
) {
Expand All @@ -216,3 +292,19 @@ fn resolve_file(opts: &CompilationOptions) -> Result<Rc<RefCell<Scope>>> {
None => Err(anyhow::anyhow!("main scope is not found")),
}
}

fn resolve_paths(opts: &CompilationOptions) -> Result<ProgramScope> {
let sess = Arc::new(ParseSession::default());
let mut program = load_all_files_under_paths(
sess,
&opts.paths.iter().map(AsRef::as_ref).collect::<Vec<_>>(),
opts.loader_opts.clone(),
None,
)?
.program;
Ok(resolve_program_with_opts(
&mut program,
opts.resolve_opts.clone(),
None,
))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "aaa"
edition = "0.0.1"
version = "0.0.1"

[dependencies]
bbb = { path = "../bbb" }
helloworld = "0.0.1"
5 changes: 5 additions & 0 deletions kclvm/query/src/test_data/get_schema_ty_under_path/aaa/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import bbb

a = bbb.B {
name: "b instance in a"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
schema Sub:
name: str

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "bbb"
edition = "0.0.1"
version = "0.0.1"

4 changes: 4 additions & 0 deletions kclvm/query/src/test_data/get_schema_ty_under_path/bbb/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
schema Base:
n: str
schema B(Base):
name: str
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
## Introduction
This is a kcl package named helloworld.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "helloworld"
edition = "0.0.1"
version = "0.0.1"

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The_first_kcl_program = 'Hello World!'
schema Hello:
name: str
11 changes: 8 additions & 3 deletions kclvm/sema/src/resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion kclvm/sema/src/resolver/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down

0 comments on commit 0d34de4

Please sign in to comment.