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: schema optional attribute validating recursively #1009

Merged
merged 1 commit into from
Jan 26, 2024
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
11 changes: 9 additions & 2 deletions kclvm/runtime/src/value/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use std::{mem::transmute_copy, os::raw::c_char};

use crate::*;

use self::walker::walk_value_mut;

#[allow(non_camel_case_types)]
pub type kclvm_context_t = Context;

Expand Down Expand Up @@ -2476,8 +2478,13 @@ pub unsafe extern "C" fn kclvm_convert_collection_value(
let tpe = c2str(tpe);
let value = type_pack_and_check(ctx, value, vec![tpe]);
let is_in_schema = ptr_as_ref(is_in_schema);
if value.is_schema() && !is_in_schema.is_truthy() {
value.schema_check_attr_optional(ctx, true);
// Schema required attribute validating.
if !is_in_schema.is_truthy() {
walk_value_mut(&value, &mut |value: &ValueRef| {
if value.is_schema() {
value.schema_check_attr_optional(ctx, true);
}
})
}
value.into_raw(ctx)
}
Expand Down
2 changes: 2 additions & 0 deletions kclvm/runtime/src/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,5 @@ pub use val_union::*;

pub mod val_yaml;
pub use val_yaml::*;

pub mod walker;
20 changes: 6 additions & 14 deletions kclvm/runtime/src/value/val_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use indexmap::IndexSet;

use crate::*;

use self::walker::walk_value_mut;

pub const SETTINGS_OUTPUT_KEY: &str = "output_type";
pub const SETTINGS_SCHEMA_TYPE_KEY: &str = "__schema_type__";
pub const SETTINGS_OUTPUT_STANDALONE: &str = "STANDALONE";
Expand Down Expand Up @@ -165,21 +167,11 @@ impl ValueRef {
if recursive {
for value in attr_map.values() {
// For composite type structures, we recursively check the schema within them.
if value.is_schema() {
value.schema_check_attr_optional(ctx, recursive);
} else if value.is_list() {
for v in &value.as_list_ref().values {
if v.is_schema() {
v.schema_check_attr_optional(ctx, recursive)
}
}
} else if value.is_dict() {
for v in value.as_dict_ref().values.values() {
if v.is_schema() {
v.schema_check_attr_optional(ctx, recursive)
}
walk_value_mut(&value, &mut |value: &ValueRef| {
if value.is_schema() {
value.schema_check_attr_optional(ctx, true);
}
}
})
}
}
}
Expand Down
47 changes: 47 additions & 0 deletions kclvm/runtime/src/value/walker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::{Value, ValueRef};

/// Walk the value recursively and deal the type using the `walk_fn`
pub fn walk_value(val: &ValueRef, walk_fn: &impl Fn(&ValueRef) -> ()) {
walk_fn(val);
match &*val.rc.borrow() {
Value::list_value(list_value) => {
for v in &list_value.values {
walk_value(v, walk_fn);
}
}
Value::dict_value(dict_value) => {
for (_, v) in &dict_value.values {
walk_value(v, walk_fn);
}
}
Value::schema_value(schema_value) => {
for (_, v) in &schema_value.config.values {
walk_value(v, walk_fn);
}
}
_ => {}
}
}

/// Walk the value recursively and mutably and deal the type using the `walk_fn`
pub fn walk_value_mut(val: &ValueRef, walk_fn: &mut impl FnMut(&ValueRef) -> ()) {
walk_fn(val);
match &*val.rc.borrow() {
Value::list_value(list_value) => {
for v in &list_value.values {
walk_value_mut(v, walk_fn);
}
}
Value::dict_value(dict_value) => {
for (_, v) in &dict_value.values {
walk_value_mut(v, walk_fn);
}
}
Value::schema_value(schema_value) => {
for (_, v) in &schema_value.config.values {
walk_value_mut(v, walk_fn);
}
}
_ => {}
}
}
9 changes: 9 additions & 0 deletions test/grammar/schema/optional_attr/fail_15/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
schema Data:
name: str
type: str

data = {
name = "data"
}

datas: [Data] = [data]
18 changes: 18 additions & 0 deletions test/grammar/schema/optional_attr/fail_15/stderr.golden.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import sys
import os

import kclvm.kcl.error as kcl_error

cwd = os.path.dirname(os.path.realpath(__file__))

kcl_error.print_kcl_error_message(
kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE,
file_msgs=[
kcl_error.ErrFileMsg(
filename=os.path.join(cwd, "main.k"),
line_no=9,
),
],
arg_msg="attribute 'type' of Data is required and can't be None or Undefined")
, file=sys.stdout
)
9 changes: 9 additions & 0 deletions test/grammar/schema/optional_attr/fail_16/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
schema Data:
name: str
type: str

data = {
name = "data"
}

datas: [[Data]] = [[data]]
18 changes: 18 additions & 0 deletions test/grammar/schema/optional_attr/fail_16/stderr.golden.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import sys
import os

import kclvm.kcl.error as kcl_error

cwd = os.path.dirname(os.path.realpath(__file__))

kcl_error.print_kcl_error_message(
kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE,
file_msgs=[
kcl_error.ErrFileMsg(
filename=os.path.join(cwd, "main.k"),
line_no=9,
),
],
arg_msg="attribute 'type' of Data is required and can't be None or Undefined")
, file=sys.stdout
)
11 changes: 11 additions & 0 deletions test/grammar/schema/optional_attr/fail_17/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
schema Data:
name: str
type: str

data = {
name = "data"
}

datas: {str:Data} = {
data = data
}
18 changes: 18 additions & 0 deletions test/grammar/schema/optional_attr/fail_17/stderr.golden.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import sys
import os

import kclvm.kcl.error as kcl_error

cwd = os.path.dirname(os.path.realpath(__file__))

kcl_error.print_kcl_error_message(
kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE,
file_msgs=[
kcl_error.ErrFileMsg(
filename=os.path.join(cwd, "main.k"),
line_no=10,
),
],
arg_msg="attribute 'type' of Data is required and can't be None or Undefined")
, file=sys.stdout
)
11 changes: 11 additions & 0 deletions test/grammar/schema/optional_attr/fail_18/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
schema Data:
name: str
type: str

data = {
name = "data"
}

datas: {str:{str:Data}} = {
data.data = data
}
18 changes: 18 additions & 0 deletions test/grammar/schema/optional_attr/fail_18/stderr.golden.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import sys
import os

import kclvm.kcl.error as kcl_error

cwd = os.path.dirname(os.path.realpath(__file__))

kcl_error.print_kcl_error_message(
kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE,
file_msgs=[
kcl_error.ErrFileMsg(
filename=os.path.join(cwd, "main.k"),
line_no=10,
),
],
arg_msg="attribute 'type' of Data is required and can't be None or Undefined")
, file=sys.stdout
)
11 changes: 11 additions & 0 deletions test/grammar/schema/optional_attr/fail_19/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
schema Data:
name: str
type: str

data = {
name = "data"
}

datas: {str:[Data]} = {
data = [data]
}
18 changes: 18 additions & 0 deletions test/grammar/schema/optional_attr/fail_19/stderr.golden.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import sys
import os

import kclvm.kcl.error as kcl_error

cwd = os.path.dirname(os.path.realpath(__file__))

kcl_error.print_kcl_error_message(
kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE,
file_msgs=[
kcl_error.ErrFileMsg(
filename=os.path.join(cwd, "main.k"),
line_no=10,
),
],
arg_msg="attribute 'type' of Data is required and can't be None or Undefined")
, file=sys.stdout
)
11 changes: 11 additions & 0 deletions test/grammar/schema/optional_attr/fail_20/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
schema Data:
name: str
type: str

data = {
name = "data"
}

datas: [{str:[Data]}] = [{
data = [data]
}]
18 changes: 18 additions & 0 deletions test/grammar/schema/optional_attr/fail_20/stderr.golden.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import sys
import os

import kclvm.kcl.error as kcl_error

cwd = os.path.dirname(os.path.realpath(__file__))

kcl_error.print_kcl_error_message(
kcl_error.get_exception(err_type=kcl_error.ErrType.EvaluationError_TYPE,
file_msgs=[
kcl_error.ErrFileMsg(
filename=os.path.join(cwd, "main.k"),
line_no=10,
),
],
arg_msg="attribute 'type' of Data is required and can't be None or Undefined")
, file=sys.stdout
)
Loading