Skip to content

Commit

Permalink
feat: impl schema instances in all package path
Browse files Browse the repository at this point in the history
Signed-off-by: peefy <xpf6677@163.com>
  • Loading branch information
Peefy committed Apr 9, 2024
1 parent 3e83ec7 commit d84376c
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 47 deletions.
15 changes: 10 additions & 5 deletions kclvm/evaluator/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use generational_arena::Index;
use indexmap::IndexMap;
use kclvm_ast::ast;
use kclvm_ast::walker::TypedResultWalker;
use kclvm_runtime::{schema_runtime_type, ConfigEntryOperationKind, ValueRef, MAIN_PKG_PATH};
use kclvm_runtime::{schema_runtime_type, ConfigEntryOperationKind, ValueRef};

use crate::lazy::{merge_setters, LazyEvalScope, LazyEvalScopeRef};
use crate::proxy::{call_schema_body, call_schema_check};
Expand Down Expand Up @@ -490,14 +490,19 @@ pub(crate) fn schema_with_config(
// avoid unexpected non idempotent calls. For example, I instantiated a MySchema in pkg1,
// but the length of the list returned by calling the instances method in other packages
// is uncertain.
if instance_pkgpath.is_empty() || instance_pkgpath == MAIN_PKG_PATH {
{
let mut ctx = s.runtime_ctx.borrow_mut();
// Record schema instance in the context
if !ctx.instances.contains_key(&runtime_type) {
ctx.instances.insert(runtime_type.clone(), vec![]);
ctx.instances
.insert(runtime_type.clone(), IndexMap::default());
}
let pkg_instance_map = ctx.instances.get_mut(&runtime_type).unwrap();
if !pkg_instance_map.contains_key(&instance_pkgpath) {
pkg_instance_map.insert(instance_pkgpath.clone(), vec![]);
}
ctx.instances
.get_mut(&runtime_type)
pkg_instance_map
.get_mut(&instance_pkgpath)
.unwrap()
.push(schema_dict.clone());
}
Expand Down
11 changes: 8 additions & 3 deletions kclvm/runtime/src/api/kclvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,13 @@ pub struct DictValue {

#[derive(PartialEq, Clone, Default, Debug)]
pub struct SchemaValue {
/// Schema name without the package path prefix.
pub name: String,
/// Schema instance package path, note is it not the schema definition package path.
pub pkgpath: String,
/// Schema values.
pub config: Box<DictValue>,
/// Schema instance config keys e.g., "a" in `MySchema {a = "foo"}`
pub config_keys: Vec<String>,
/// schema config meta information including filename, line and column.
pub config_meta: ValueRef,
Expand Down Expand Up @@ -338,8 +342,9 @@ pub struct Context {
pub imported_pkgpath: HashSet<String>,
/// Runtime arguments for the option function.
pub app_args: HashMap<String, u64>,
/// All schema instances
pub instances: HashMap<String, Vec<ValueRef>>,
/// All schema instances, the first key is the schema runtime type and
/// the second key is the schema instance package path
pub instances: IndexMap<String, IndexMap<String, Vec<ValueRef>>>,
/// All schema types
pub all_schemas: HashMap<String, SchemaType>,
/// Import graph
Expand Down Expand Up @@ -396,7 +401,7 @@ impl BacktraceFrame {
impl Context {
pub fn new() -> Self {
Context {
instances: HashMap::new(),
instances: IndexMap::default(),
panic_info: PanicInfo {
kcl_func: "kclvm_main".to_string(),
..Default::default()
Expand Down
87 changes: 50 additions & 37 deletions kclvm/runtime/src/value/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,15 +290,18 @@ pub unsafe extern "C" fn kclvm_value_schema_with_config(
Some(args.clone()),
Some(kwargs.clone()),
);
if record_instance.is_truthy()
&& (instance_pkgpath.is_empty() || instance_pkgpath == MAIN_PKG_PATH)
{
if record_instance.is_truthy() {
// Record schema instance in the context
if !ctx.instances.contains_key(&runtime_type) {
ctx.instances.insert(runtime_type.clone(), vec![]);
ctx.instances
.insert(runtime_type.clone(), IndexMap::default());
}
let pkg_instance_map = ctx.instances.get_mut(&runtime_type).unwrap();
if !pkg_instance_map.contains_key(&instance_pkgpath) {
pkg_instance_map.insert(instance_pkgpath.clone(), vec![]);
}
ctx.instances
.get_mut(&runtime_type)
pkg_instance_map
.get_mut(&instance_pkgpath)
.unwrap()
.push(schema_dict.clone());
}
Expand Down Expand Up @@ -2060,44 +2063,29 @@ pub unsafe extern "C" fn kclvm_schema_instances(
let kwargs = ptr_as_ref(kwargs);
if let Some(val) = args.pop_arg_first() {
let function = val.as_function();
let main_pkg = args.arg_0().or_else(|| kwargs.kwarg("main_pkg"));
let main_pkg = if let Some(v) = main_pkg {
let full_pkg = args.arg_0().or_else(|| kwargs.kwarg("full_pkg"));
let full_pkg = if let Some(v) = full_pkg {
v.is_truthy()
} else {
true
false
};
let runtime_type = &function.runtime_type;
if ctx_ref.instances.contains_key(runtime_type) {
let mut list = ValueRef::list(None);
for v in ctx_ref.instances.get(runtime_type).unwrap() {
if v.is_schema() {
let schema = v.as_schema();
if main_pkg {
if schema.pkgpath == MAIN_PKG_PATH {
list.list_append(v)
}
} else {
list.list_append(v)
}
} else if v.is_dict() {
let runtime_type = v
.get_potential_schema_type()
.unwrap_or(runtime_type.to_string());
let names: Vec<&str> = runtime_type.rsplit('.').collect();
let name = names[0];
let pkgpath = names[1];
let v = v.dict_to_schema(
name,
pkgpath,
&[],
&ValueRef::dict(None),
&ValueRef::dict(None),
None,
None,
);
list.list_append(&v);
let instance_map = ctx_ref.instances.get(runtime_type).unwrap();
if full_pkg {
for (_, v_list) in instance_map {
collect_schema_instances(&mut list, &v_list, runtime_type)
}
}
} else {
// Get the schema instances only located at the main package.
if let Some(v_list) = instance_map.get(MAIN_PKG_PATH) {
collect_schema_instances(&mut list, &v_list, runtime_type)
}
if let Some(v_list) = instance_map.get("") {
collect_schema_instances(&mut list, &v_list, runtime_type)
}
};
list.into_raw(ctx_ref)
} else {
kclvm_value_List(ctx)
Expand All @@ -2107,6 +2095,31 @@ pub unsafe extern "C" fn kclvm_schema_instances(
}
}

fn collect_schema_instances(list: &mut ValueRef, v_list: &[ValueRef], runtime_type: &str) {
for v in v_list {
if v.is_schema() {
list.list_append(v)
} else if v.is_dict() {
let runtime_type = v
.get_potential_schema_type()
.unwrap_or(runtime_type.to_string());
let names: Vec<&str> = runtime_type.rsplit('.').collect();
let name = names[0];
let pkgpath = names[1];
let v = v.dict_to_schema(
name,
pkgpath,
&[],
&ValueRef::dict(None),
&ValueRef::dict(None),
None,
None,
);
list.list_append(&v);
}
}
}

#[no_mangle]
#[runtime_fn]
pub unsafe extern "C" fn kclvm_schema_value_check(
Expand Down
11 changes: 9 additions & 2 deletions kclvm/sema/src/resolver/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use crate::builtin::system_module::{get_system_module_members, UNITS, UNITS_NUMB
use crate::builtin::{get_system_member_function_ty, STRING_MEMBER_FUNCTIONS};
use crate::resolver::Resolver;
use crate::ty::TypeKind::Schema;
use crate::ty::{DictType, ModuleKind, Type, TypeKind, TypeRef, SCHEMA_MEMBER_FUNCTIONS};
use crate::ty::{
DictType, ModuleKind, Parameter, Type, TypeKind, TypeRef, SCHEMA_MEMBER_FUNCTIONS,
};
use kclvm_error::diagnostic::Range;
use kclvm_error::*;

Expand Down Expand Up @@ -72,7 +74,12 @@ impl<'ctx> Resolver<'ctx> {
Arc::new(Type::function(
Some(obj.clone()),
Type::list_ref(self.any_ty()),
&[],
&[Parameter {
name: "full_pkg".to_string(),
ty: Type::bool_ref(),
// Default value is False
has_default: true,
}],
"",
false,
None,
Expand Down
5 changes: 5 additions & 0 deletions test/grammar/schema/instances/complex/complex_5/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import pkg

x0 = pkg.Person {}
all_main_persons = pkg.Person.instances()
all_persons = pkg.Person.instances(True)
12 changes: 12 additions & 0 deletions test/grammar/schema/instances/complex/complex_5/pkg/pkg.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
schema Data:
id: int = 1

schema Person:
name: str = "kcl"
age: int = 1
data: Data = Data {}

x0 = Person {}
x1 = Person {
age = 101
}
23 changes: 23 additions & 0 deletions test/grammar/schema/instances/complex/complex_5/stdout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
x0:
name: kcl
age: 1
data:
id: 1
all_main_persons:
- name: kcl
age: 1
data:
id: 1
all_persons:
- name: kcl
age: 1
data:
id: 1
- name: kcl
age: 101
data:
id: 1
- name: kcl
age: 1
data:
id: 1

0 comments on commit d84376c

Please sign in to comment.