Skip to content

Commit

Permalink
fix: evaluator runtime schema type get attr and type cast (#1425)
Browse files Browse the repository at this point in the history
Signed-off-by: peefy <[email protected]>
  • Loading branch information
Peefy authored Jun 20, 2024
1 parent 9873aaf commit 63b2368
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 42 deletions.
2 changes: 2 additions & 0 deletions kclvm/evaluator/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@ impl<'ctx> TypedResultWalker<'ctx> for Evaluator<'ctx> {
ctx: Rc::new(RefCell::new(SchemaEvalContext::new_with_node(
schema_stmt.clone(),
Index::from_raw_parts(self.frames.borrow().len(), 0),
SchemaEvalContext::get_parent_schema(self, &schema_stmt.parent_name),
SchemaEvalContext::get_mixin_schemas(self, &schema_stmt.mixins),
))),
body,
check,
Expand Down
123 changes: 82 additions & 41 deletions kclvm/evaluator/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub struct SchemaEvalContext {
pub node: Rc<ast::SchemaStmt>,
pub scope: Option<LazyEvalScopeRef>,
pub index: Index,
pub parent: Option<Index>,
pub mixins: Vec<Index>,
pub value: ValueRef,
pub config: ValueRef,
pub config_meta: ValueRef,
Expand All @@ -39,11 +41,18 @@ pub struct SchemaEvalContext {

impl SchemaEvalContext {
#[inline]
pub fn new_with_node(node: ast::SchemaStmt, index: Index) -> Self {
pub fn new_with_node(
node: ast::SchemaStmt,
index: Index,
parent: Option<Index>,
mixins: Vec<Index>,
) -> Self {
Self {
node: Rc::new(node),
scope: None,
index,
parent,
mixins,
value: ValueRef::dict(None),
config: ValueRef::dict(None),
config_meta: ValueRef::dict(None),
Expand All @@ -58,6 +67,8 @@ impl SchemaEvalContext {
Rc::new(RefCell::new(Self {
node: self.node.clone(),
index: self.index,
parent: self.parent,
mixins: self.mixins.clone(),
scope: None,
value: ValueRef::dict(None),
config,
Expand Down Expand Up @@ -99,28 +110,17 @@ impl SchemaEvalContext {
self.is_sub_schema = true;
}

/// Update parent schema and mixin schema information
/// Update parent schema and mixin schema information in the current scope.
pub fn get_parent_schema(
s: &Evaluator,
ctx: &SchemaEvalContext,
) -> Option<(Index, SchemaEvalContextRef)> {
if let Some(parent_name) = &ctx.node.parent_name {
parent: &Option<Box<ast::Node<ast::Identifier>>>,
) -> Option<Index> {
if let Some(parent) = parent {
let func = s
.walk_identifier_with_ctx(&parent_name.node, &ast::ExprContext::Load, None)
.walk_identifier_with_ctx(&parent.node, &ast::ExprContext::Load, None)
.expect(kcl_error::RUNTIME_ERROR_MSG);
if let Some(index) = func.try_get_proxy() {
let frame = {
let frames = s.frames.borrow();
frames
.get(index)
.expect(kcl_error::INTERNAL_ERROR_MSG)
.clone()
};
if let Proxy::Schema(schema) = &frame.proxy {
Some((index, schema.ctx.clone()))
} else {
None
}
Some(index)
} else {
None
}
Expand All @@ -132,10 +132,10 @@ impl SchemaEvalContext {
/// Update parent schema and mixin schema information
pub fn get_mixin_schemas(
s: &Evaluator,
ctx: &SchemaEvalContext,
) -> Vec<(Index, SchemaEvalContextRef)> {
mixins: &[Box<ast::Node<ast::Identifier>>],
) -> Vec<Index> {
let mut results = vec![];
for mixin in &ctx.node.mixins {
for mixin in mixins {
let func = s
.walk_identifier_with_ctx(&mixin.node, &ast::ExprContext::Load, None)
.expect(kcl_error::RUNTIME_ERROR_MSG);
Expand All @@ -147,8 +147,8 @@ impl SchemaEvalContext {
.expect(kcl_error::INTERNAL_ERROR_MSG)
.clone()
};
if let Proxy::Schema(schema) = &frame.proxy {
results.push((index, schema.ctx.clone()))
if let Proxy::Schema(_) = &frame.proxy {
results.push(index);
}
}
}
Expand All @@ -164,8 +164,17 @@ impl SchemaEvalContext {
}
}
}
if let Some((_, parent)) = SchemaEvalContext::get_parent_schema(s, &ctx.borrow()) {
return SchemaEvalContext::has_attr(s, &parent, name);
if let Some(index) = ctx.borrow().parent {
let frame = {
let frames = s.frames.borrow();
frames
.get(index)
.expect(kcl_error::INTERNAL_ERROR_MSG)
.clone()
};
if let Proxy::Schema(schema) = &frame.proxy {
return SchemaEvalContext::has_attr(s, &schema.ctx, name);
}
}
false
}
Expand All @@ -175,8 +184,18 @@ impl SchemaEvalContext {
if ctx.borrow().node.index_signature.is_some() {
return true;
}
if let Some((_, parent)) = SchemaEvalContext::get_parent_schema(s, &ctx.borrow()) {
return SchemaEvalContext::has_index_signature(s, &parent);

if let Some(index) = ctx.borrow().parent {
let frame = {
let frames = s.frames.borrow();
frames
.get(index)
.expect(kcl_error::INTERNAL_ERROR_MSG)
.clone()
};
if let Proxy::Schema(schema) = &frame.proxy {
return SchemaEvalContext::has_index_signature(s, &schema.ctx);
}
}
false
}
Expand All @@ -199,18 +218,29 @@ impl SchemaEvalContext {
}
}

/// Init the lazy scope used to
/// Init the lazy scope used to cache the lazy evaluation result.
pub fn init_lazy_scope(&mut self, s: &Evaluator, index: Option<Index>) {
// TODO: cache the lazy scope cross different schema instances.
let mut setters = IndexMap::new();
// Parent schema setters
if let Some((idx, parent)) = SchemaEvalContext::get_parent_schema(s, self) {
{
let mut parent = parent.borrow_mut();
if let Some(idx) = self.parent {
let frame = {
let frames = s.frames.borrow();
frames
.get(idx)
.expect(kcl_error::INTERNAL_ERROR_MSG)
.clone()
};
if let Proxy::Schema(schema) = &frame.proxy {
let mut parent = schema.ctx.borrow_mut();
parent.init_lazy_scope(s, Some(idx));
}
if let Some(scope) = &parent.borrow().scope {
merge_variables_and_setters(&mut self.value, &mut setters, &scope.borrow().setters);
if let Some(scope) = &parent.scope {
merge_variables_and_setters(
&mut self.value,
&mut setters,
&scope.borrow().setters,
);
}
}
}
// Self setters
Expand All @@ -220,13 +250,24 @@ impl SchemaEvalContext {
&s.emit_setters(&self.node.body, index),
);
// Mixin schema setters
for (idx, mixin) in SchemaEvalContext::get_mixin_schemas(s, self) {
{
let mut mixin = mixin.borrow_mut();
mixin.init_lazy_scope(s, Some(idx));
}
if let Some(scope) = &mixin.borrow().scope {
merge_variables_and_setters(&mut self.value, &mut setters, &scope.borrow().setters);
for idx in &self.mixins {
let frame = {
let frames = s.frames.borrow();
frames
.get(*idx)
.expect(kcl_error::INTERNAL_ERROR_MSG)
.clone()
};
if let Proxy::Schema(schema) = &frame.proxy {
let mut mixin = schema.ctx.borrow_mut();
mixin.init_lazy_scope(s, Some(*idx));
if let Some(scope) = &mixin.scope {
merge_variables_and_setters(
&mut self.value,
&mut setters,
&scope.borrow().setters,
);
}
}
}
self.scope = Some(Rc::new(RefCell::new(LazyEvalScope {
Expand Down
2 changes: 1 addition & 1 deletion kclvm/evaluator/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ pub fn convert_collection_value(s: &Evaluator, value: &ValueRef, tpe: &str) -> V
.clone()
};
let schema = if let Proxy::Schema(caller) = &frame.proxy {
// Try convert the config to schema, if failed, return the config
// Try convert the config to schema, if failed, return the config directly.
if !SchemaEvalContext::is_fit_config(s, &caller.ctx, value) {
return value.clone();
}
Expand Down
Empty file.
11 changes: 11 additions & 0 deletions test/grammar/import/import_with_complex_types_0/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import types

hosts0: {str:types.Host} = {
foo: {host: "foo.example.net"}
bar: {host: "bar.example.net"}
}

hosts1: {str:types.HostPort} = {
foo: {host: "foo.example.net", port: 80}
bar: {host: "bar.example.net", port: 80}
}
5 changes: 5 additions & 0 deletions test/grammar/import/import_with_complex_types_0/types/host.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
schema Host:
host: str

schema HostPort(Host):
port: int
Empty file.
11 changes: 11 additions & 0 deletions test/grammar/import/import_with_complex_types_1/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import types

hosts0: [types.Host] = [
{host: "foo.example.net"}
{host: "bar.example.net"}
]

hosts1: [types.HostPort] = [
{host: "foo.example.net", port: 80}
{host: "bar.example.net", port: 80}
]
5 changes: 5 additions & 0 deletions test/grammar/import/import_with_complex_types_1/types/host.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
schema Host:
host: str

schema HostPort(Host):
port: int

0 comments on commit 63b2368

Please sign in to comment.