Skip to content

Commit

Permalink
fix: schema optional attribute validating recursively (#1009)
Browse files Browse the repository at this point in the history
Signed-off-by: peefy <[email protected]>
  • Loading branch information
Peefy committed Jan 26, 2024
1 parent 5d8d023 commit 90f25ad
Show file tree
Hide file tree
Showing 16 changed files with 234 additions and 16 deletions.
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
)

0 comments on commit 90f25ad

Please sign in to comment.