diff --git a/.github/workflows/build-test-macos-arm64.yml b/.github/workflows/build-test-macos-arm64.yml index 0eb694759..e19730bc1 100644 --- a/.github/workflows/build-test-macos-arm64.yml +++ b/.github/workflows/build-test-macos-arm64.yml @@ -1,5 +1,6 @@ name: Build and Test on MacOS ARCH64 - +env: + MACOSX_DEPLOYMENT_TARGET: '10.13' on: ["push", "pull_request"] jobs: build-and-test: diff --git a/kclvm/ast/src/ast.rs b/kclvm/ast/src/ast.rs index 40f74812e..8cac4f1f7 100644 --- a/kclvm/ast/src/ast.rs +++ b/kclvm/ast/src/ast.rs @@ -1070,7 +1070,6 @@ pub struct ConfigEntry { pub key: Option>, pub value: NodeRef, pub operation: ConfigEntryOperation, - pub insert_index: isize, } /// CheckExpr, e.g. diff --git a/kclvm/ast_pretty/src/node.rs b/kclvm/ast_pretty/src/node.rs index 5c8f3f57d..96dfc58b6 100644 --- a/kclvm/ast_pretty/src/node.rs +++ b/kclvm/ast_pretty/src/node.rs @@ -842,9 +842,6 @@ impl<'p> Printer<'p> { match &item.node.key { Some(key) => { let print_right_brace_count = self.write_config_key(key); - if item.node.insert_index >= 0 { - self.write(&format!("[{}]", item.node.insert_index)); - } if !matches!(item.node.operation, ast::ConfigEntryOperation::Union) { self.write_space(); } diff --git a/kclvm/compiler/src/codegen/llvm/context.rs b/kclvm/compiler/src/codegen/llvm/context.rs index 4967707c1..0bc28f3f4 100644 --- a/kclvm/compiler/src/codegen/llvm/context.rs +++ b/kclvm/compiler/src/codegen/llvm/context.rs @@ -998,11 +998,13 @@ impl<'ctx> DerivedValueCalculationMethods for LLVMCodeGenContext<'ctx> { key: &str, value: Self::Value, op: i32, - insert_index: i32, + insert_index: Option, ) { let name = self.native_global_string(key, "").into(); let op = self.native_int_value(op); - let insert_index = self.native_int_value(insert_index); + let has_insert_index = insert_index.is_some(); + let has_insert_index = self.native_i8_value(if has_insert_index { 1 } else { 0 }); + let insert_index = self.native_int_value(insert_index.unwrap_or(-1)); self.build_void_call( &ApiFunc::kclvm_dict_insert.name(), &[ @@ -1012,6 +1014,7 @@ impl<'ctx> DerivedValueCalculationMethods for LLVMCodeGenContext<'ctx> { value, op, insert_index, + has_insert_index, ], ); } @@ -1025,10 +1028,12 @@ impl<'ctx> DerivedValueCalculationMethods for LLVMCodeGenContext<'ctx> { key: Self::Value, value: Self::Value, op: i32, - insert_index: i32, + insert_index: Option, ) { let op = self.native_int_value(op); - let insert_index = self.native_int_value(insert_index); + let has_insert_index = insert_index.is_some(); + let has_insert_index = self.native_i8_value(if has_insert_index { 1 } else { 0 }); + let insert_index = self.native_int_value(insert_index.unwrap_or(-1)); self.build_void_call( &ApiFunc::kclvm_dict_insert_value.name(), &[ @@ -1038,6 +1043,7 @@ impl<'ctx> DerivedValueCalculationMethods for LLVMCodeGenContext<'ctx> { value, op, insert_index, + has_insert_index, ], ); } @@ -1576,6 +1582,12 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { i8_type.const_int(v as u64, false) } + /// Get LLVM i8 zero value + pub fn native_i8_value(&self, v: i8) -> BasicValueEnum<'ctx> { + let i8_type = self.context.i8_type(); + i8_type.const_int(v as u64, false).into() + } + /// Construct a LLVM int value using i32 pub fn native_int_value(&self, v: i32) -> BasicValueEnum<'ctx> { let i32_type = self.context.i32_type(); @@ -2356,14 +2368,14 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } // Deal scalars for scalar in scalars.iter() { - self.dict_safe_insert(global_dict, SCALAR_KEY, *scalar, 0, -1); + self.dict_safe_insert(global_dict, SCALAR_KEY, *scalar, 0, None); } // Deal global variables for (name, ptr) in globals.iter() { let value = self.builder.build_load(*ptr, ""); let value_dict = self.dict_value(); - self.dict_safe_insert(value_dict, name.as_str(), value, 0, -1); - self.dict_safe_insert(global_dict, SCALAR_KEY, value_dict, 0, -1); + self.dict_safe_insert(value_dict, name.as_str(), value, 0, None); + self.dict_safe_insert(global_dict, SCALAR_KEY, value_dict, 0, None); } // Plan result to json string. self.build_call( @@ -2386,11 +2398,13 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { key: &str, value: BasicValueEnum<'ctx>, op: i32, - insert_index: i32, + insert_index: Option, ) { let name = self.native_global_string(key, "").into(); let op = self.native_int_value(op); - let insert_index = self.native_int_value(insert_index); + let has_insert_index = insert_index.is_some(); + let has_insert_index = self.native_i8_value(if has_insert_index { 1 } else { 0 }); + let insert_index = self.native_int_value(insert_index.unwrap_or(-1)); self.build_void_call( &ApiFunc::kclvm_dict_safe_insert.name(), &[ @@ -2400,6 +2414,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { value, op, insert_index, + has_insert_index, ], ); } @@ -2413,11 +2428,13 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { key: &str, value: BasicValueEnum<'ctx>, op: i32, - insert_index: i32, + insert_index: Option, ) { let name = self.native_global_string(key, "").into(); let op = self.native_int_value(op); - let insert_index = self.native_int_value(insert_index); + let has_insert_index = insert_index.is_some(); + let has_insert_index = self.native_i8_value(if has_insert_index { 1 } else { 0 }); + let insert_index = self.native_int_value(insert_index.unwrap_or(-1)); self.build_void_call( &ApiFunc::kclvm_dict_merge.name(), &[ @@ -2427,6 +2444,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { value, op, insert_index, + has_insert_index, ], ); } diff --git a/kclvm/compiler/src/codegen/llvm/node.rs b/kclvm/compiler/src/codegen/llvm/node.rs index 5412b2ca8..2e73694d9 100644 --- a/kclvm/compiler/src/codegen/llvm/node.rs +++ b/kclvm/compiler/src/codegen/llvm/node.rs @@ -1538,10 +1538,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { &fn_name.name(), &[self.current_runtime_ctx_ptr(), org_value, value], ); - self.dict_merge(schema_value, name, value, 1, -1); + self.dict_merge(schema_value, name, value, 1, None); } // Assign - _ => self.dict_merge(schema_value, name, value, 1, -1), + _ => self.dict_merge(schema_value, name, value, 1, None), } } self.br(is_not_override_else_block); @@ -1595,10 +1595,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { &fn_name.name(), &[self.current_runtime_ctx_ptr(), org_value, value], ); - self.dict_merge(schema_value, name, value, 1, -1); + self.dict_merge(schema_value, name, value, 1, None); } // Assign - _ => self.dict_merge(schema_value, name, value, 1, -1), + _ => self.dict_merge(schema_value, name, value, 1, None), } } self.br(end_block); @@ -1781,7 +1781,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { } else { self.none_value() }; - self.dict_insert(dict_value, name.node.as_str(), value, 0, -1); + self.dict_insert(dict_value, name.node.as_str(), value, 0, None); } let pkgpath = self.native_global_string_value(&self.current_pkgpath()); let is_in_schema = self.is_in_schema() || self.is_in_schema_expr(); @@ -2053,7 +2053,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { } else { self.none_value() }; - self.dict_insert(dict_value, name.node.as_str(), value, 0, -1); + self.dict_insert(dict_value, name.node.as_str(), value, 0, None); } let pkgpath = self.native_global_string_value(&self.current_pkgpath()); let schema = self.build_call( @@ -2597,7 +2597,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } else { self.none_value() }; - self.dict_insert(dict_value, name.node.as_str(), value, 0, -1); + self.dict_insert(dict_value, name.node.as_str(), value, 0, None); } let name = match &decorator.func.node { ast::Expr::Identifier(ident) if ident.names.len() == 1 => ident.names[0].clone(), @@ -2808,7 +2808,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { key, self.value_deep_copy(value), op.value(), - -1, + None, ); } } @@ -2843,7 +2843,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { for item in items { let value = self.walk_expr(&item.node.value)?; if let Some(key) = &item.node.key { - let mut insert_index = -1; + let mut insert_index = None; let optional_name = match &key.node { ast::Expr::Identifier(identifier) => Some(identifier.names[0].node.clone()), ast::Expr::StringLit(string_lit) => Some(string_lit.value.clone()), @@ -2851,11 +2851,20 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let mut name = None; if let ast::Expr::Identifier(identifier) = &subscript.value.node { if let Some(index_node) = &subscript.index { + // Insert index if let ast::Expr::NumberLit(number) = &index_node.node { if let ast::NumberLitValue::Int(v) = number.value { - insert_index = v; + insert_index = Some(v as i32); name = Some(identifier.names[0].node.clone()) } + } else if let ast::Expr::Unary(unary_expr) = &index_node.node { + // Negative insert index + if let ast::Expr::NumberLit(number) = &unary_expr.operand.node { + if let ast::NumberLitValue::Int(v) = number.value { + insert_index = Some(-v as i32); + name = Some(identifier.names[0].node.clone()) + } + } } } } @@ -2873,7 +2882,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { key, value, item.node.operation.value(), - insert_index as i32, + insert_index, ); if let Some(name) = &optional_name { let value = diff --git a/kclvm/compiler/src/codegen/llvm/schema.rs b/kclvm/compiler/src/codegen/llvm/schema.rs index a3b18d6ee..24fe35198 100644 --- a/kclvm/compiler/src/codegen/llvm/schema.rs +++ b/kclvm/compiler/src/codegen/llvm/schema.rs @@ -89,7 +89,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { match &stmt.node { ast::Stmt::Unification(unification_stmt) => { let name = &unification_stmt.target.node.names[0].node; - self.dict_merge(schema_value, name, value, 0, -1); + self.dict_merge(schema_value, name, value, 0, None); if is_in_if { in_if_names.push(name.to_string()); } else { @@ -105,7 +105,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { ast::Stmt::Assign(assign_stmt) => { for target in &assign_stmt.targets { let name = &target.node.names[0].node; - self.dict_merge(schema_value, name, value, 0, -1); + self.dict_merge(schema_value, name, value, 0, None); if is_in_if { in_if_names.push(name.to_string()); } else { @@ -122,7 +122,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { ast::Stmt::AugAssign(aug_assign_stmt) => { let target = &aug_assign_stmt.target; let name = &target.node.names[0].node; - self.dict_merge(schema_value, name, value, 0, -1); + self.dict_merge(schema_value, name, value, 0, None); if is_in_if { in_if_names.push(name.to_string()); } else { @@ -186,7 +186,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } ast::Stmt::SchemaAttr(schema_attr) => { let name = schema_attr.name.node.as_str(); - self.dict_merge(schema_value, name, value, 0, -1); + self.dict_merge(schema_value, name, value, 0, None); if is_in_if { in_if_names.push(name.to_string()); } else { @@ -324,7 +324,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let config_value = phi.as_basic_value(); if self.scope_level() >= INNER_LEVEL && !self.local_vars.borrow().contains(name) { if let Some(value) = value { - self.dict_merge(schema_value, name, value, 1, -1); + self.dict_merge(schema_value, name, value, 1, None); } self.value_union(schema_value, config_value); let cal_map = self diff --git a/kclvm/compiler/src/codegen/traits/value.rs b/kclvm/compiler/src/codegen/traits/value.rs index ac4e05509..89529440e 100644 --- a/kclvm/compiler/src/codegen/traits/value.rs +++ b/kclvm/compiler/src/codegen/traits/value.rs @@ -165,7 +165,7 @@ pub trait DerivedValueCalculationMethods: ValueMethods + ValueCalculationMethods key: Self::Value, value: Self::Value, op: i32, - insert_index: i32, + insert_index: Option, ); /// Insert a dict entry including key, value, op and insert_index into the dict, /// and the type of key is `&str` @@ -175,13 +175,13 @@ pub trait DerivedValueCalculationMethods: ValueMethods + ValueCalculationMethods key: &str, value: Self::Value, op: i32, - insert_index: i32, + insert_index: Option, ) { self.dict_insert_with_key_value(dict, self.string_value(key), value, op, insert_index); } /// Insert a dict entry with the override = attribute operator including key, value into the dict. fn dict_insert_override_item(&self, dict: Self::Value, key: &str, value: Self::Value) { - self.dict_insert(dict, key, value, 1, -1); + self.dict_insert(dict, key, value, 1, None); } /// Dict contains key. fn dict_contains_key(&self, dict: Self::Value, key: &str) -> Self::Value { diff --git a/kclvm/evaluator/src/calculation.rs b/kclvm/evaluator/src/calculation.rs index d82d28ce4..c526e632a 100644 --- a/kclvm/evaluator/src/calculation.rs +++ b/kclvm/evaluator/src/calculation.rs @@ -209,14 +209,14 @@ impl<'ctx> Evaluator<'ctx> { key: &str, value: &ValueRef, op: &ast::ConfigEntryOperation, - insert_index: i32, + insert_index: Option, ) { let op = match op { ast::ConfigEntryOperation::Union => ConfigEntryOperationKind::Union, ast::ConfigEntryOperation::Override => ConfigEntryOperationKind::Override, ast::ConfigEntryOperation::Insert => ConfigEntryOperationKind::Insert, }; - self.dict_merge_key_value_pair(dict, key, value, op, insert_index, false); + self.dict_merge_key_value_pair(dict, key, value, op, insert_index, true); } /// Insert a dict entry including key, value, op and insert_index into the dict, @@ -228,7 +228,7 @@ impl<'ctx> Evaluator<'ctx> { key: &str, value: &ValueRef, op: &ast::ConfigEntryOperation, - insert_index: i32, + insert_index: Option, ) { let op = match op { ast::ConfigEntryOperation::Union => ConfigEntryOperationKind::Union, @@ -259,7 +259,14 @@ impl<'ctx> Evaluator<'ctx> { /// Insert an entry including key and value into the dict, and merge the original entry. #[inline] pub(crate) fn dict_insert_merge_value(&self, dict: &mut ValueRef, key: &str, value: &ValueRef) { - self.dict_merge_key_value_pair(dict, key, value, ConfigEntryOperationKind::Union, -1, true); + self.dict_merge_key_value_pair( + dict, + key, + value, + ConfigEntryOperationKind::Union, + None, + true, + ); } /// Set dict key with the value. When the dict is a schema and resolve schema validations. @@ -292,14 +299,16 @@ impl<'ctx> Evaluator<'ctx> { key: &str, v: &ValueRef, op: ConfigEntryOperationKind, - insert_index: i32, + insert_index: Option, idempotent_check: bool, ) { if p.is_config() { let mut dict: DictValue = Default::default(); dict.values.insert(key.to_string(), v.clone()); dict.ops.insert(key.to_string(), op); - dict.insert_indexs.insert(key.to_string(), insert_index); + if let Some(index) = insert_index { + dict.insert_indexs.insert(key.to_string(), index); + } union_entry( self, p, diff --git a/kclvm/evaluator/src/node.rs b/kclvm/evaluator/src/node.rs index 16a6e66c9..cfb16a89b 100644 --- a/kclvm/evaluator/src/node.rs +++ b/kclvm/evaluator/src/node.rs @@ -490,8 +490,7 @@ impl<'ctx> TypedResultWalker<'ctx> for Evaluator<'ctx> { config_value.dict_get_attr_operator(name), Some(ConfigEntryOperationKind::Override) ); - let without_index = - matches!(config_value.dict_get_insert_index(name), Some(-1) | None); + let without_index = matches!(config_value.dict_get_insert_index(name), None); is_override_op && without_index }; if !is_override_attr { @@ -512,7 +511,7 @@ impl<'ctx> TypedResultWalker<'ctx> for Evaluator<'ctx> { name, &value, &ast::ConfigEntryOperation::Override, - -1, + None, ); } // Assign @@ -521,7 +520,7 @@ impl<'ctx> TypedResultWalker<'ctx> for Evaluator<'ctx> { name, &value, &ast::ConfigEntryOperation::Override, - -1, + None, ), } } @@ -555,7 +554,7 @@ impl<'ctx> TypedResultWalker<'ctx> for Evaluator<'ctx> { name, &value, &ast::ConfigEntryOperation::Override, - -1, + None, ); } // Assign @@ -564,7 +563,7 @@ impl<'ctx> TypedResultWalker<'ctx> for Evaluator<'ctx> { name, &value, &ast::ConfigEntryOperation::Override, - -1, + None, ), } } @@ -1510,7 +1509,7 @@ impl<'ctx> Evaluator<'ctx> { &key.as_str(), &value.deep_copy(), op, - -1, + None, ); } } @@ -1535,20 +1534,29 @@ impl<'ctx> Evaluator<'ctx> { let mut config_value = self.dict_value(); for item in items { let value = self.walk_expr(&item.node.value)?; - if let Some(key) = &item.node.key { - let mut insert_index = -1; - let optional_name = match &key.node { + if let Some(key_node) = &item.node.key { + let mut insert_index = None; + let optional_name = match &key_node.node { ast::Expr::Identifier(identifier) => Some(identifier.names[0].node.clone()), ast::Expr::StringLit(string_lit) => Some(string_lit.value.clone()), ast::Expr::Subscript(subscript) => { let mut name = None; if let ast::Expr::Identifier(identifier) = &subscript.value.node { if let Some(index_node) = &subscript.index { + // Insert index if let ast::Expr::NumberLit(number) = &index_node.node { if let ast::NumberLitValue::Int(v) = number.value { - insert_index = v; + insert_index = Some(v as i32); name = Some(identifier.names[0].node.clone()) } + } else if let ast::Expr::Unary(unary_expr) = &index_node.node { + // Negative insert index + if let ast::Expr::NumberLit(number) = &unary_expr.operand.node { + if let ast::NumberLitValue::Int(v) = number.value { + insert_index = Some(-v as i32); + name = Some(identifier.names[0].node.clone()) + } + } } } } @@ -1559,14 +1567,14 @@ impl<'ctx> Evaluator<'ctx> { // Store a local variable for every entry key. let key = match &optional_name { Some(name) if !self.is_local_var(name) => self.string_value(name), - _ => self.walk_expr(key)?, + _ => self.walk_expr(key_node)?, }; self.dict_insert( &mut config_value, &key.as_str(), &value, &item.node.operation, - insert_index as i32, + insert_index, ); if let Some(name) = &optional_name { let value = self.dict_get_value(&config_value, name); diff --git a/kclvm/evaluator/src/schema.rs b/kclvm/evaluator/src/schema.rs index b9711b58e..1e86b0a5d 100644 --- a/kclvm/evaluator/src/schema.rs +++ b/kclvm/evaluator/src/schema.rs @@ -737,14 +737,14 @@ fn schema_relaxed_attr_update_and_check( key.as_str(), &index_sign_value.deep_copy(), &ConfigEntryOperationKind::Override, - &-1, + None, ); s.dict_merge_key_value_pair( schema_value, key.as_str(), value, op.clone(), - -1, + None, false, ); let value = schema_value.dict_get_value(key).unwrap(); @@ -864,7 +864,7 @@ impl<'ctx> Evaluator<'ctx> { name, value, &ast::ConfigEntryOperation::Override, - -1, + None, ); } self.value_union(&mut schema_value, &config_value); diff --git a/kclvm/evaluator/src/ty.rs b/kclvm/evaluator/src/ty.rs index c46c8e738..9bdd2f973 100644 --- a/kclvm/evaluator/src/ty.rs +++ b/kclvm/evaluator/src/ty.rs @@ -117,7 +117,7 @@ pub fn convert_collection_value(s: &Evaluator, value: &ValueRef, tpe: &str) -> V .ops .get(k) .unwrap_or(&ConfigEntryOperationKind::Union); - let index = dict_ref.insert_indexs.get(k).unwrap_or(&-1); + let index = dict_ref.insert_indexs.get(k); expected_dict.dict_update_entry(k, &expected_value, op, index) } expected_dict diff --git a/kclvm/evaluator/src/union.rs b/kclvm/evaluator/src/union.rs index 9a2a5a16d..81cda4056 100644 --- a/kclvm/evaluator/src/union.rs +++ b/kclvm/evaluator/src/union.rs @@ -2,7 +2,9 @@ use crate::*; use kclvm_runtime::unification::value_subsume; -use kclvm_runtime::{ConfigEntryOperationKind, DictValue, UnionContext, UnionOptions, Value}; +use kclvm_runtime::{ + must_normalize_index, ConfigEntryOperationKind, DictValue, UnionContext, UnionOptions, Value, +}; use self::ty::resolve_schema; @@ -35,61 +37,119 @@ fn do_union( } else { &ConfigEntryOperationKind::Union }; - let index = if let Some(idx) = delta.insert_indexs.get(k) { - *idx - } else { - -1 - }; - if !obj.values.contains_key(k) { + let index = delta.insert_indexs.get(k); + if !obj.values.contains_key(k) && index.is_none() { obj.values.insert(k.clone(), v.clone()); } else { match operation { - ConfigEntryOperationKind::Union => { - let obj_value = obj.values.get_mut(k).unwrap(); - if opts.idempotent_check && !value_subsume(v, obj_value, false) { - union_context.conflict = true; - union_context.path_backtrace.push(k.clone()); - union_context.obj_json = if obj_value.is_config() { - "{...}".to_string() - } else if obj_value.is_list() { - "[...]".to_string() - } else { - obj_value.to_json_string() - }; + ConfigEntryOperationKind::Union => match index { + Some(index) => { + let index = *index; + if let Some(origin_value) = obj.values.get_mut(k) { + if !origin_value.is_list() { + panic!( + "only list attribute can be union value with the index {}", + index + ); + } + let value = origin_value.list_get(index as isize); + if let Some(mut value) = value { + if opts.idempotent_check && !value_subsume(v, &value, false) { + union_context.conflict = true; + union_context + .path_backtrace + .push(format!("{}[{}]", k, index)); + union_context.obj_json = if value.is_config() { + "{...}".to_string() + } else if value.is_list() { + "[...]".to_string() + } else { + value.to_json_string() + }; - union_context.delta_json = if v.is_config() { - "{...}".to_string() - } else if v.is_list() { - "[...]".to_string() + union_context.delta_json = if v.is_config() { + "{...}".to_string() + } else if v.is_list() { + "[...]".to_string() + } else { + v.to_json_string() + }; + return; + } + let union_value = + union(s, &mut value, v, false, opts, union_context); + if union_context.conflict { + union_context.path_backtrace.push(k.clone()); + return; + } + let index = must_normalize_index(index, origin_value.len()); + origin_value.list_set(index, &union_value); + } else { + panic!("only non-empty list attribute can be union value with the index {}", index); + } } else { - v.to_json_string() - }; - return; + panic!("only non-empty list attribute can be union value with the index {}", index); + } } - union(s, obj_value, v, false, opts, union_context); - if union_context.conflict { - union_context.path_backtrace.push(k.clone()); - return; + None => { + if let Some(obj_value) = obj.values.get_mut(k) { + if opts.idempotent_check && !value_subsume(v, obj_value, false) { + union_context.conflict = true; + union_context.path_backtrace.push(k.clone()); + union_context.obj_json = if obj_value.is_config() { + "{...}".to_string() + } else if obj_value.is_list() { + "[...]".to_string() + } else { + obj_value.to_json_string() + }; + + union_context.delta_json = if v.is_config() { + "{...}".to_string() + } else if v.is_list() { + "[...]".to_string() + } else { + v.to_json_string() + }; + return; + } + union(s, obj_value, v, false, opts, union_context); + if union_context.conflict { + union_context.path_backtrace.push(k.clone()); + return; + } + } else { + obj.values.insert(k.clone(), v.clone()); + } } - } + }, ConfigEntryOperationKind::Override => { - if index < 0 { - obj.values.insert(k.clone(), v.clone()); - } else { - let origin_value = obj.values.get_mut(k).unwrap(); - if !origin_value.is_list() { - panic!("only list attribute can be inserted value"); + match index { + Some(index) => { + let index = *index; + let origin_value = obj.values.get_mut(k); + if let Some(origin_value) = origin_value { + if !origin_value.is_list() { + panic!("only list attribute can be override value with the index {}", index); + } + let index = must_normalize_index(index, origin_value.len()); + if v.is_undefined() { + origin_value.list_remove_at(index as usize); + } else { + origin_value.list_must_set(index as usize, v); + } + } else { + panic!("only list attribute can be override value with the index {}", index); + } } - if v.is_none_or_undefined() { - origin_value.list_remove_at(index as usize); - } else { - origin_value.list_set(index as usize, v); + None => { + obj.values.insert(k.clone(), v.clone()); } } } ConfigEntryOperationKind::Insert => { - let origin_value = obj.values.get_mut(k).unwrap(); - if origin_value.is_none_or_undefined() { + let origin_value = obj.values.get_mut(k); + if origin_value.is_none() || origin_value.unwrap().is_none_or_undefined() { let list = ValueRef::list(None); obj.values.insert(k.to_string(), list); } @@ -99,21 +159,27 @@ fn do_union( } match (&mut *origin_value.rc.borrow_mut(), &*v.rc.borrow()) { (Value::list_value(origin_value), Value::list_value(value)) => { - if index == -1 { - for elem in value.values.iter() { - origin_value.values.push(elem.clone()); + match index { + Some(index) => { + let index = *index; + let mut insert_index = + must_normalize_index(index, origin_value.values.len()); + for v in &value.values { + origin_value.values.insert(insert_index, v.clone()); + insert_index += 1; + } } - } else if index >= 0 { - let mut insert_index = index; - for v in &value.values { - origin_value - .values - .insert(insert_index as usize, v.clone()); - insert_index += 1; + None => { + for elem in value.values.iter() { + origin_value.values.push(elem.clone()); + } } } } - _ => panic!("only list attribute can be inserted value"), + _ => panic!( + "only list attribute can be inserted value, the origin value type is {} and got value type is {}", + origin_value.type_str(), v.type_str() + ), }; } } @@ -121,7 +187,7 @@ fn do_union( } }; - // whether to union schema vars and resolve it and do the check of schema + // Whether to union schema vars and resolve it and do the check of schema. let mut union_schema = false; let mut pkgpath: String = "".to_string(); let mut name: String = "".to_string(); diff --git a/kclvm/parser/src/parser/expr.rs b/kclvm/parser/src/parser/expr.rs index d12cf4a40..11813bd7f 100644 --- a/kclvm/parser/src/parser/expr.rs +++ b/kclvm/parser/src/parser/expr.rs @@ -1479,7 +1479,6 @@ impl<'a> Parser<'a> { key, value, operation, - insert_index: -1, }, self.sess.struct_token_loc(token, self.prev_token), )) @@ -1747,7 +1746,6 @@ impl<'a> Parser<'a> { key: expr0, value: expr1, operation: op, - insert_index: -1 }, pos )); @@ -1777,7 +1775,6 @@ impl<'a> Parser<'a> { key: expr0, value: expr1, operation: op, - insert_index: -1 }, pos )); @@ -1838,7 +1835,6 @@ impl<'a> Parser<'a> { key: expr0, value: expr1, operation: op, - insert_index: -1 }, pos )); diff --git a/kclvm/query/src/override.rs b/kclvm/query/src/override.rs index b183c18dd..350bc2ccf 100644 --- a/kclvm/query/src/override.rs +++ b/kclvm/query/src/override.rs @@ -427,7 +427,6 @@ impl<'ctx> MutSelfMutWalker<'ctx> for OverrideTransformer { )))), value: self.clone_override_value(), operation: self.operation.clone(), - insert_index: -1, }))], }))) }; @@ -570,7 +569,6 @@ impl<'ctx> MutSelfMutWalker<'ctx> for OverrideTransformer { )))), value: self.clone_override_value(), operation: self.operation.clone(), - insert_index: -1, }))); self.has_override = true; } @@ -704,7 +702,6 @@ impl OverrideTransformer { key: Some(Box::new(ast::Node::dummy_node(ast::Expr::Identifier(key)))), value: self.clone_override_value(), operation: self.operation.clone(), - insert_index: -1, }))); changed = true; } diff --git a/kclvm/runtime/src/_kclvm.bc b/kclvm/runtime/src/_kclvm.bc index 2fc81056d..2c3c25798 100644 Binary files a/kclvm/runtime/src/_kclvm.bc and b/kclvm/runtime/src/_kclvm.bc differ diff --git a/kclvm/runtime/src/_kclvm.h b/kclvm/runtime/src/_kclvm.h index e5baa4b5d..292bfd666 100644 --- a/kclvm/runtime/src/_kclvm.h +++ b/kclvm/runtime/src/_kclvm.h @@ -263,11 +263,11 @@ kclvm_value_ref_t* kclvm_dict_get_value_by_path(kclvm_context_t* ctx, kclvm_valu kclvm_bool_t kclvm_dict_has_value(kclvm_value_ref_t* p, kclvm_char_t* key); -void kclvm_dict_insert(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); +void kclvm_dict_insert(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); void kclvm_dict_insert_unpack(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* v); -void kclvm_dict_insert_value(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); +void kclvm_dict_insert_value(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); kclvm_bool_t kclvm_dict_is_override_attr(kclvm_value_ref_t* p, kclvm_char_t* key); @@ -275,11 +275,11 @@ kclvm_value_ref_t* kclvm_dict_keys(kclvm_context_t* ctx, kclvm_value_ref_t* p); kclvm_size_t kclvm_dict_len(kclvm_value_ref_t* p); -void kclvm_dict_merge(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); +void kclvm_dict_merge(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); void kclvm_dict_remove(kclvm_value_ref_t* p, kclvm_char_t* key); -void kclvm_dict_safe_insert(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); +void kclvm_dict_safe_insert(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); void kclvm_dict_set_value(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* val); diff --git a/kclvm/runtime/src/_kclvm.ll b/kclvm/runtime/src/_kclvm.ll index 448df7a86..01401bd0d 100644 --- a/kclvm/runtime/src/_kclvm.ll +++ b/kclvm/runtime/src/_kclvm.ll @@ -226,11 +226,11 @@ declare %kclvm_value_ref_t* @kclvm_dict_get_value_by_path(%kclvm_context_t* %ctx declare %kclvm_bool_t @kclvm_dict_has_value(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); -declare void @kclvm_dict_insert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +declare void @kclvm_dict_insert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); declare void @kclvm_dict_insert_unpack(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %v); -declare void @kclvm_dict_insert_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +declare void @kclvm_dict_insert_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); declare %kclvm_bool_t @kclvm_dict_is_override_attr(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); @@ -238,11 +238,11 @@ declare %kclvm_value_ref_t* @kclvm_dict_keys(%kclvm_context_t* %ctx, %kclvm_valu declare %kclvm_size_t @kclvm_dict_len(%kclvm_value_ref_t* %p); -declare void @kclvm_dict_merge(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +declare void @kclvm_dict_merge(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); declare void @kclvm_dict_remove(%kclvm_value_ref_t* %p, %kclvm_char_t* %key); -declare void @kclvm_dict_safe_insert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +declare void @kclvm_dict_safe_insert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); declare void @kclvm_dict_set_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %val); diff --git a/kclvm/runtime/src/_kclvm_api_spec.rs b/kclvm/runtime/src/_kclvm_api_spec.rs index 3c4478f91..93defc117 100644 --- a/kclvm/runtime/src/_kclvm_api_spec.rs +++ b/kclvm/runtime/src/_kclvm_api_spec.rs @@ -347,24 +347,24 @@ // api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_dict_values(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p); // api-spec: kclvm_dict_insert -// api-spec(c): void kclvm_dict_insert(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); -// api-spec(llvm): declare void @kclvm_dict_insert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +// api-spec(c): void kclvm_dict_insert(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); +// api-spec(llvm): declare void @kclvm_dict_insert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); // api-spec: kclvm_dict_merge -// api-spec(c): void kclvm_dict_merge(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); -// api-spec(llvm): declare void @kclvm_dict_merge(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +// api-spec(c): void kclvm_dict_merge(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); +// api-spec(llvm): declare void @kclvm_dict_merge(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); // api-spec: kclvm_dict_insert_value -// api-spec(c): void kclvm_dict_insert_value(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); -// api-spec(llvm): declare void @kclvm_dict_insert_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +// api-spec(c): void kclvm_dict_insert_value(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); +// api-spec(llvm): declare void @kclvm_dict_insert_value(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); // api-spec: kclvm_dict_update_key_value // api-spec(c): void kclvm_dict_update_key_value(kclvm_value_ref_t* p, kclvm_value_ref_t* key, kclvm_value_ref_t* v); // api-spec(llvm): declare void @kclvm_dict_update_key_value(%kclvm_value_ref_t* %p, %kclvm_value_ref_t* %key, %kclvm_value_ref_t* %v); // api-spec: kclvm_dict_safe_insert -// api-spec(c): void kclvm_dict_safe_insert(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index); -// api-spec(llvm): declare void @kclvm_dict_safe_insert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index); +// api-spec(c): void kclvm_dict_safe_insert(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_char_t* key, kclvm_value_ref_t* v, kclvm_size_t op, kclvm_size_t insert_index, kclvm_bool_t has_insert_index); +// api-spec(llvm): declare void @kclvm_dict_safe_insert(%kclvm_context_t* %ctx, %kclvm_value_ref_t* %p, %kclvm_char_t* %key, %kclvm_value_ref_t* %v, %kclvm_size_t %op, %kclvm_size_t %insert_index, %kclvm_bool_t %has_insert_index); // api-spec: kclvm_dict_insert_unpack // api-spec(c): void kclvm_dict_insert_unpack(kclvm_context_t* ctx, kclvm_value_ref_t* p, kclvm_value_ref_t* v); diff --git a/kclvm/runtime/src/manifests/tests.rs b/kclvm/runtime/src/manifests/tests.rs index aa7923c4b..5c38c539d 100644 --- a/kclvm/runtime/src/manifests/tests.rs +++ b/kclvm/runtime/src/manifests/tests.rs @@ -74,7 +74,7 @@ fn test_kclvm_manifests_yaml_stream() { "opts", &opts, ConfigEntryOperationKind::Override, - -1, + None, ); kclvm_manifests_yaml_stream(&mut ctx, &args, &kwargs); assert_eq!( diff --git a/kclvm/runtime/src/stdlib/builtin.rs b/kclvm/runtime/src/stdlib/builtin.rs index 901a4bd87..4c49632ee 100644 --- a/kclvm/runtime/src/stdlib/builtin.rs +++ b/kclvm/runtime/src/stdlib/builtin.rs @@ -453,7 +453,7 @@ pub fn dict(ctx: &mut Context, iterable: Option<&ValueRef>) -> ValueRef { let k = iter.cur_key.clone(); match &*k.rc.borrow() { Value::str_value(str) => { - result.dict_insert(ctx, str.as_str(), &elem, Default::default(), -1); + result.dict_insert(ctx, str.as_str(), &elem, Default::default(), None); } _ => { let mut elem_iter = elem.iter(); @@ -462,7 +462,7 @@ pub fn dict(ctx: &mut Context, iterable: Option<&ValueRef>) -> ValueRef { } let k = elem_iter.next(val).unwrap().to_string(); let v = elem_iter.next(val).unwrap(); - result.dict_insert(ctx, k.as_str(), v, Default::default(), -1); + result.dict_insert(ctx, k.as_str(), v, Default::default(), None); } }; } diff --git a/kclvm/runtime/src/value/api.rs b/kclvm/runtime/src/value/api.rs index 8a788da23..25c694d01 100644 --- a/kclvm/runtime/src/value/api.rs +++ b/kclvm/runtime/src/value/api.rs @@ -1095,6 +1095,7 @@ pub unsafe extern "C" fn kclvm_dict_insert( v: *const kclvm_value_ref_t, op: kclvm_size_t, insert_index: kclvm_size_t, + has_insert_index: kclvm_bool_t, ) { let p = mut_ptr_as_ref(p); let v = ptr_as_ref(v); @@ -1103,7 +1104,11 @@ pub unsafe extern "C" fn kclvm_dict_insert( c2str(key), v, ConfigEntryOperationKind::from_i32(op), - insert_index, + if has_insert_index != 0 { + Some(insert_index) + } else { + None + }, ); } @@ -1116,6 +1121,7 @@ pub unsafe extern "C" fn kclvm_dict_merge( v: *const kclvm_value_ref_t, op: kclvm_size_t, insert_index: kclvm_size_t, + has_insert_index: kclvm_bool_t, ) { let p = mut_ptr_as_ref(p); let v = ptr_as_ref(v); @@ -1135,7 +1141,11 @@ pub unsafe extern "C" fn kclvm_dict_merge( key, &v, ConfigEntryOperationKind::from_i32(op), - insert_index, + if has_insert_index != 0 { + Some(insert_index) + } else { + None + }, ); } else { p.dict_merge( @@ -1143,7 +1153,11 @@ pub unsafe extern "C" fn kclvm_dict_merge( key, v, ConfigEntryOperationKind::from_i32(op), - insert_index, + if has_insert_index != 0 { + Some(insert_index) + } else { + None + }, ); } } @@ -1157,6 +1171,7 @@ pub unsafe extern "C" fn kclvm_dict_insert_value( v: *const kclvm_value_ref_t, op: kclvm_size_t, insert_index: kclvm_size_t, + has_insert_index: kclvm_bool_t, ) { let p = mut_ptr_as_ref(p); let v = ptr_as_ref(v); @@ -1167,7 +1182,11 @@ pub unsafe extern "C" fn kclvm_dict_insert_value( key.as_str(), v, ConfigEntryOperationKind::from_i32(op), - insert_index, + if has_insert_index != 0 { + Some(insert_index) + } else { + None + }, ); } @@ -1194,11 +1213,12 @@ pub unsafe extern "C" fn kclvm_dict_safe_insert( v: *const kclvm_value_ref_t, op: kclvm_size_t, insert_index: kclvm_size_t, + has_insert_index: kclvm_bool_t, ) { if p.is_null() || key.is_null() || v.is_null() { return; } - kclvm_dict_insert(ctx, p, key, v, op, insert_index); + kclvm_dict_insert(ctx, p, key, v, op, insert_index, has_insert_index); } #[no_mangle] @@ -2129,9 +2149,9 @@ pub unsafe extern "C" fn kclvm_schema_value_check( key.as_str(), &index_sign_value.deep_copy(), &ConfigEntryOperationKind::Override, - &-1, + None, ); - schema_value.dict_insert(ctx, key.as_str(), value, op.clone(), -1); + schema_value.dict_insert(ctx, key.as_str(), value, op.clone(), None); let value = schema_value.dict_get_value(key).unwrap(); schema_value.dict_update_key_value( key.as_str(), diff --git a/kclvm/runtime/src/value/val_clone.rs b/kclvm/runtime/src/value/val_clone.rs index 2294cde54..5ba0494b4 100644 --- a/kclvm/runtime/src/value/val_clone.rs +++ b/kclvm/runtime/src/value/val_clone.rs @@ -56,13 +56,8 @@ impl ValueRef { let mut dict = ValueRef::from(Value::dict_value(Box::new(DictValue::new(&[])))); for (key, val) in &v.values { let op = v.ops.get(key).unwrap_or(&ConfigEntryOperationKind::Union); - let index = v.insert_indexs.get(key).unwrap_or(&-1); - dict.dict_update_entry( - key.as_str(), - &val.deep_copy(), - &op.clone(), - &index.clone(), - ); + let index = v.insert_indexs.get(key); + dict.dict_update_entry(key.as_str(), &val.deep_copy(), &op.clone(), index); } dict.set_potential_schema_type(&v.potential_schema.clone().unwrap_or_default()); dict @@ -78,13 +73,8 @@ impl ValueRef { .ops .get(key) .unwrap_or(&ConfigEntryOperationKind::Union); - let index = v.config.insert_indexs.get(key).unwrap_or(&-1); - dict.dict_update_entry( - key.as_str(), - &val.deep_copy(), - &op.clone(), - &index.clone(), - ); + let index = v.config.insert_indexs.get(key); + dict.dict_update_entry(key.as_str(), &val.deep_copy(), &op.clone(), index); if let Some(type_str) = v.config.attr_map.get(key) { dict.update_attr_map(key, type_str); } diff --git a/kclvm/runtime/src/value/val_dict.rs b/kclvm/runtime/src/value/val_dict.rs index 3145d7728..9d45ae8f2 100644 --- a/kclvm/runtime/src/value/val_dict.rs +++ b/kclvm/runtime/src/value/val_dict.rs @@ -128,10 +128,8 @@ impl ValueRef { /// Dict get value e.g., {k1 = v1, k2 = v2}.get_attr_operator(k1) == Some(ConfigEntryOperationKind::Override) pub fn dict_get_insert_index(&self, key: &str) -> Option { match &*self.rc.borrow() { - Value::dict_value(ref dict) => Some(*dict.insert_indexs.get(key).unwrap_or(&-1)), - Value::schema_value(ref schema) => { - Some(*schema.config.insert_indexs.get(key).unwrap_or(&-1)) - } + Value::dict_value(ref dict) => dict.insert_indexs.get(key).cloned(), + Value::schema_value(ref schema) => schema.config.insert_indexs.get(key).cloned(), _ => None, } } @@ -148,12 +146,8 @@ impl ValueRef { } else { &ConfigEntryOperationKind::Union }; - let index = if let Some(idx) = dict.insert_indexs.get(key) { - *idx - } else { - -1 - }; - d.dict_update_entry(key, value, op, &index); + let index = dict.insert_indexs.get(key); + d.dict_update_entry(key, value, op, index); d.set_potential_schema_type(&dict.potential_schema.clone().unwrap_or_default()); Some(d) } else { @@ -169,12 +163,8 @@ impl ValueRef { } else { &ConfigEntryOperationKind::Union }; - let index = if let Some(idx) = schema.config.insert_indexs.get(key) { - *idx - } else { - -1 - }; - d.dict_update_entry(key, value, op, &index); + let index = schema.config.insert_indexs.get(key); + d.dict_update_entry(key, value, op, index); d.set_potential_schema_type( &schema.config.potential_schema.clone().unwrap_or_default(), ); @@ -200,7 +190,7 @@ impl ValueRef { .ops .get(key) .unwrap_or(&ConfigEntryOperationKind::Union); - let index = dict.insert_indexs.get(key).unwrap_or(&-1); + let index = dict.insert_indexs.get(key); d.dict_update_entry(key, value, op, index); } } @@ -217,7 +207,7 @@ impl ValueRef { .ops .get(key) .unwrap_or(&ConfigEntryOperationKind::Union); - let index = schema.config.insert_indexs.get(key).unwrap_or(&-1); + let index = schema.config.insert_indexs.get(key); d.dict_update_entry(key, value, op, index); } } @@ -248,7 +238,7 @@ impl ValueRef { for key in keys { if dict.values.contains_key(key) { let value = dict.values.get(key).unwrap(); - let index = dict.insert_indexs.get(key).unwrap_or(&-1); + let index = dict.insert_indexs.get(key); d.dict_update_entry(key, value, op, index); } } @@ -260,7 +250,7 @@ impl ValueRef { for key in keys { if schema.config.values.contains_key(key) { let value = schema.config.values.get(key).unwrap(); - let index = schema.config.insert_indexs.get(key).unwrap_or(&-1); + let index = schema.config.insert_indexs.get(key); d.dict_update_entry(key, value, op, index); } } @@ -319,7 +309,7 @@ impl ValueRef { key: &str, val: &ValueRef, op: &ConfigEntryOperationKind, - index: &i32, + index: Option<&i32>, ) { let mut binding = self.rc.borrow_mut(); let dict = match &mut *binding { @@ -329,7 +319,9 @@ impl ValueRef { }; dict.values.insert(key.to_string(), val.clone()); dict.ops.insert(key.to_string(), op.clone()); - dict.insert_indexs.insert(key.to_string(), *index); + if let Some(index) = index { + dict.insert_indexs.insert(key.to_string(), *index); + } } /// Insert key value pair with the idempotent check. @@ -340,7 +332,7 @@ impl ValueRef { key: &str, v: &ValueRef, op: ConfigEntryOperationKind, - insert_index: i32, + insert_index: Option, ) { self.dict_merge_key_value_pair(ctx, key, v, op, insert_index, true); } @@ -352,7 +344,7 @@ impl ValueRef { key: &str, v: &ValueRef, op: ConfigEntryOperationKind, - insert_index: i32, + insert_index: Option, ) { self.dict_merge_key_value_pair(ctx, key, v, op, insert_index, false); } @@ -364,7 +356,7 @@ impl ValueRef { key: &str, v: &ValueRef, op: ConfigEntryOperationKind, - insert_index: i32, + insert_index: Option, idempotent_check: bool, ) { if ctx.cfg.debug_mode { @@ -391,7 +383,9 @@ impl ValueRef { let mut dict: DictValue = Default::default(); dict.values.insert(key.to_string(), v.clone()); dict.ops.insert(key.to_string(), op); - dict.insert_indexs.insert(key.to_string(), insert_index); + if let Some(insert_index) = insert_index { + dict.insert_indexs.insert(key.to_string(), insert_index); + } self.union_entry( ctx, &ValueRef::from(Value::dict_value(Box::new(dict))), @@ -521,7 +515,7 @@ mod test_value_dict { key, &ValueRef::str(val), &ConfigEntryOperationKind::Union, - &-1, + None, ); } for (key, val) in update_entries { diff --git a/kclvm/runtime/src/value/val_get_set.rs b/kclvm/runtime/src/value/val_get_set.rs index 67b3bf377..ceecb7a75 100644 --- a/kclvm/runtime/src/value/val_get_set.rs +++ b/kclvm/runtime/src/value/val_get_set.rs @@ -43,14 +43,14 @@ mod test_value_get { "a", &ValueRef::str("a-value"), Default::default(), - 0, + None, ); dict.dict_insert( &mut ctx, "b", &ValueRef::str("b-value"), Default::default(), - 0, + None, ); list_int.list_set(1, &dict); diff --git a/kclvm/runtime/src/value/val_json.rs b/kclvm/runtime/src/value/val_json.rs index 8cbc64da4..ec19f626d 100644 --- a/kclvm/runtime/src/value/val_json.rs +++ b/kclvm/runtime/src/value/val_json.rs @@ -368,7 +368,13 @@ impl ValueRef { let mut dict = Self::dict(None); for (name, value) in values { let v = Self::parse_json(ctx, value); - dict.dict_insert(ctx, name.as_ref(), &v, ConfigEntryOperationKind::Union, -1); + dict.dict_insert( + ctx, + name.as_ref(), + &v, + ConfigEntryOperationKind::Union, + None, + ); } dict } diff --git a/kclvm/runtime/src/value/val_list.rs b/kclvm/runtime/src/value/val_list.rs index b1551293b..3f4399572 100644 --- a/kclvm/runtime/src/value/val_list.rs +++ b/kclvm/runtime/src/value/val_list.rs @@ -114,6 +114,15 @@ impl ValueRef { } } + pub fn list_must_set(&mut self, i: usize, v: &Self) { + match &mut *self.rc.borrow_mut() { + Value::list_value(list) => { + list.values.as_mut_slice()[i] = v.clone(); + } + _ => panic!("Invalid list object in list_set"), + } + } + pub fn list_pop(&mut self) -> Option { match &mut *self.rc.borrow_mut() { Value::list_value(list) => list.values.pop(), diff --git a/kclvm/runtime/src/value/val_schema.rs b/kclvm/runtime/src/value/val_schema.rs index 207cfc8a5..6a6b337e0 100644 --- a/kclvm/runtime/src/value/val_schema.rs +++ b/kclvm/runtime/src/value/val_schema.rs @@ -295,10 +295,12 @@ impl ValueRef { .ops .get(k) .unwrap_or(&ConfigEntryOperationKind::Union); - let index = value.config.insert_indexs.get(k).unwrap_or(&-1); + let index = value.config.insert_indexs.get(k); values.insert(k.clone(), v.clone()); ops.insert(k.clone(), op.clone()); - insert_indexs.insert(k.clone(), *index); + if let Some(index) = index { + insert_indexs.insert(k.clone(), *index); + } } } } @@ -416,7 +418,7 @@ mod test_value_schema { key, &ValueRef::str(val), &ConfigEntryOperationKind::Union, - &-1, + None, ); } assert_ne!(schema1, schema2); diff --git a/kclvm/runtime/src/value/val_type.rs b/kclvm/runtime/src/value/val_type.rs index abd3fe56a..94ebb14bf 100644 --- a/kclvm/runtime/src/value/val_type.rs +++ b/kclvm/runtime/src/value/val_type.rs @@ -235,7 +235,7 @@ pub fn convert_collection_value(ctx: &mut Context, value: &ValueRef, tpe: &str) .ops .get(k) .unwrap_or(&ConfigEntryOperationKind::Union); - let index = dict_ref.insert_indexs.get(k).unwrap_or(&-1); + let index = dict_ref.insert_indexs.get(k); expected_dict.dict_update_entry(k, &expected_value, op, index) } expected_dict diff --git a/kclvm/runtime/src/value/val_union.rs b/kclvm/runtime/src/value/val_union.rs index 70a4933f8..5cc74c610 100644 --- a/kclvm/runtime/src/value/val_union.rs +++ b/kclvm/runtime/src/value/val_union.rs @@ -34,6 +34,23 @@ impl Default for UnionOptions { } } +/// Normalize negative index into positive index with the length. +pub fn must_normalize_index(index: i32, len: usize) -> usize { + if index < 0 { + let pos_index = index + len as i32; + if pos_index >= 0 { + pos_index as usize + } else { + panic!( + "index out of bounds: the len is {} but the index is {}", + len, index + ) + } + } else { + index as usize + } +} + impl ValueRef { fn do_union( &mut self, @@ -64,61 +81,121 @@ impl ValueRef { } else { &ConfigEntryOperationKind::Union }; - let index = if let Some(idx) = delta.insert_indexs.get(k) { - *idx - } else { - -1 - }; - if !obj.values.contains_key(k) { + let index = delta.insert_indexs.get(k); + if !obj.values.contains_key(k) && index.is_none() { obj.values.insert(k.clone(), v.clone()); } else { match operation { - ConfigEntryOperationKind::Union => { - let obj_value = obj.values.get_mut(k).unwrap(); - if opts.idempotent_check && !value_subsume(v, obj_value, false) { - union_context.conflict = true; - union_context.path_backtrace.push(k.clone()); - union_context.obj_json = if obj_value.is_config() { - "{...}".to_string() - } else if obj_value.is_list() { - "[...]".to_string() - } else { - obj_value.to_json_string() - }; + ConfigEntryOperationKind::Union => match index { + Some(index) => { + let index = *index; + if let Some(origin_value) = obj.values.get_mut(k) { + if !origin_value.is_list() { + panic!( + "only list attribute can be union value with the index {}", + index + ); + } + let value = origin_value.list_get(index as isize); + if let Some(mut value) = value { + if opts.idempotent_check && !value_subsume(v, &value, false) + { + union_context.conflict = true; + union_context + .path_backtrace + .push(format!("{}[{}]", k, index)); + union_context.obj_json = if value.is_config() { + "{...}".to_string() + } else if value.is_list() { + "[...]".to_string() + } else { + value.to_json_string() + }; - union_context.delta_json = if v.is_config() { - "{...}".to_string() - } else if v.is_list() { - "[...]".to_string() + union_context.delta_json = if v.is_config() { + "{...}".to_string() + } else if v.is_list() { + "[...]".to_string() + } else { + v.to_json_string() + }; + return; + } + let union_value = + value.union(ctx, v, false, opts, union_context); + if union_context.conflict { + union_context.path_backtrace.push(k.clone()); + return; + } + let index = must_normalize_index(index, origin_value.len()); + origin_value.list_set(index, &union_value); + } else { + panic!("only non-empty list attribute can be union value with the index {}", index); + } } else { - v.to_json_string() - }; - return; - } - obj_value.union(ctx, v, false, opts, union_context); - if union_context.conflict { - union_context.path_backtrace.push(k.clone()); - return; + panic!("only non-empty list attribute can be union value with the index {}", index); + } } - } - ConfigEntryOperationKind::Override => { - if index < 0 { - obj.values.insert(k.clone(), v.clone()); - } else { - let origin_value = obj.values.get_mut(k).unwrap(); - if !origin_value.is_list() { - panic!("only list attribute can be inserted value"); + None => { + if let Some(obj_value) = obj.values.get_mut(k) { + if opts.idempotent_check && !value_subsume(v, obj_value, false) + { + union_context.conflict = true; + union_context.path_backtrace.push(k.clone()); + union_context.obj_json = if obj_value.is_config() { + "{...}".to_string() + } else if obj_value.is_list() { + "[...]".to_string() + } else { + obj_value.to_json_string() + }; + + union_context.delta_json = if v.is_config() { + "{...}".to_string() + } else if v.is_list() { + "[...]".to_string() + } else { + v.to_json_string() + }; + return; + } + obj_value.union(ctx, v, false, opts, union_context); + if union_context.conflict { + union_context.path_backtrace.push(k.clone()); + return; + } + } else { + obj.values.insert(k.clone(), v.clone()); } - if v.is_none_or_undefined() { - origin_value.list_remove_at(index as usize); + } + }, + ConfigEntryOperationKind::Override => match index { + Some(index) => { + let index = *index; + let origin_value = obj.values.get_mut(k); + if let Some(origin_value) = origin_value { + if !origin_value.is_list() { + panic!("only list attribute can be override value with the index {}", index); + } + let index = must_normalize_index(index, origin_value.len()); + if v.is_undefined() { + origin_value.list_remove_at(index as usize); + } else { + origin_value.list_must_set(index as usize, v); + } } else { - origin_value.list_set(index as usize, v); + panic!("only list attribute can be override value with the index {}", index); } } - } + None => { + obj.values.insert(k.clone(), v.clone()); + } + }, ConfigEntryOperationKind::Insert => { - let origin_value = obj.values.get_mut(k).unwrap(); - if origin_value.is_none_or_undefined() { + let origin_value = obj.values.get_mut(k); + if origin_value.is_none() + || origin_value.unwrap().is_none_or_undefined() + { let list = ValueRef::list(None); obj.values.insert(k.to_string(), list); } @@ -128,21 +205,27 @@ impl ValueRef { } match (&mut *origin_value.rc.borrow_mut(), &*v.rc.borrow()) { (Value::list_value(origin_value), Value::list_value(value)) => { - if index == -1 { - for elem in value.values.iter() { - origin_value.values.push(elem.clone()); + match index { + Some(index) => { + let index = *index; + let mut insert_index = + must_normalize_index(index, origin_value.values.len()); + for v in &value.values { + origin_value.values.insert(insert_index, v.clone()); + insert_index += 1; + } } - } else if index >= 0 { - let mut insert_index = index; - for v in &value.values { - origin_value - .values - .insert(insert_index as usize, v.clone()); - insert_index += 1; + None => { + for elem in value.values.iter() { + origin_value.values.push(elem.clone()); + } } } } - _ => panic!("only list attribute can be inserted value"), + _ => panic!( + "only list attribute can be inserted value, the origin value type is {} and got value type is {}", + origin_value.type_str(), v.type_str() + ), }; } } @@ -150,7 +233,7 @@ impl ValueRef { } }; - //union schema vars + // Whether to union schema vars and resolve it and do the check of schema. let mut union_schema = false; let mut pkgpath: String = "".to_string(); let mut name: String = "".to_string(); @@ -371,37 +454,37 @@ mod test_value_union { let mut ctx = Context::new(); let cases = [ ( - vec![("key", "value", ConfigEntryOperationKind::Union, -1)], - vec![("key", "value", ConfigEntryOperationKind::Union, -1)], - vec![("key", "value", ConfigEntryOperationKind::Union, -1)], + vec![("key", "value", ConfigEntryOperationKind::Union, None)], + vec![("key", "value", ConfigEntryOperationKind::Union, None)], + vec![("key", "value", ConfigEntryOperationKind::Union, None)], ), ( - vec![("key", "value", ConfigEntryOperationKind::Override, -1)], - vec![("key", "value", ConfigEntryOperationKind::Override, -1)], - vec![("key", "value", ConfigEntryOperationKind::Override, -1)], + vec![("key", "value", ConfigEntryOperationKind::Override, None)], + vec![("key", "value", ConfigEntryOperationKind::Override, None)], + vec![("key", "value", ConfigEntryOperationKind::Override, None)], ), ( - vec![("key", "value1", ConfigEntryOperationKind::Union, -1)], - vec![("key", "value2", ConfigEntryOperationKind::Override, -1)], - vec![("key", "value2", ConfigEntryOperationKind::Override, -1)], + vec![("key", "value1", ConfigEntryOperationKind::Union, None)], + vec![("key", "value2", ConfigEntryOperationKind::Override, None)], + vec![("key", "value2", ConfigEntryOperationKind::Override, None)], ), ( vec![ - ("key1", "value1", ConfigEntryOperationKind::Union, -1), - ("key2", "value2", ConfigEntryOperationKind::Union, -1), + ("key1", "value1", ConfigEntryOperationKind::Union, None), + ("key2", "value2", ConfigEntryOperationKind::Union, None), ], vec![ ( "key1", "override_value1", ConfigEntryOperationKind::Override, - -1, + None, ), ( "key2", "override_value2", ConfigEntryOperationKind::Override, - -1, + None, ), ], vec![ @@ -409,13 +492,13 @@ mod test_value_union { "key1", "override_value1", ConfigEntryOperationKind::Override, - -1, + None, ), ( "key2", "override_value2", ConfigEntryOperationKind::Override, - -1, + None, ), ], ), @@ -424,20 +507,20 @@ mod test_value_union { let mut left_value = ValueRef::dict(None); let mut right_value = ValueRef::dict(None); for (key, val, op, index) in left_entries { - left_value.dict_update_entry(key, &ValueRef::str(val), &op, &index); + left_value.dict_update_entry(key, &ValueRef::str(val), &op, index); } for (key, val, op, index) in right_entries { - right_value.dict_update_entry(key, &ValueRef::str(val), &op, &index); + right_value.dict_update_entry(key, &ValueRef::str(val), &op, index); } let result = left_value.bin_bit_or(&mut ctx, &right_value); for (key, val, op, index) in expected { let result_dict = result.as_dict_ref(); let result_val = result_dict.values.get(key).unwrap().as_str(); let result_op = result_dict.ops.get(key).unwrap(); - let result_index = result_dict.insert_indexs.get(key).unwrap(); + let result_index = result_dict.insert_indexs.get(key); assert_eq!(result_val, val); assert_eq!(*result_op, op); - assert_eq!(*result_index, index); + assert_eq!(result_index.cloned(), index); } } } @@ -446,38 +529,48 @@ mod test_value_union { let mut ctx = Context::new(); let cases = [ ( - vec![("key", vec![0, 1], ConfigEntryOperationKind::Override, -1)], - vec![("key", vec![2, 3], ConfigEntryOperationKind::Insert, -1)], + vec![("key", vec![0, 1], ConfigEntryOperationKind::Override, None)], + vec![("key", vec![2, 3], ConfigEntryOperationKind::Insert, None)], vec![( "key", vec![0, 1, 2, 3], ConfigEntryOperationKind::Insert, - -1, + None, )], ), ( - vec![("key", vec![0, 1], ConfigEntryOperationKind::Override, -1)], - vec![("key", vec![2, 3], ConfigEntryOperationKind::Insert, 0)], - vec![("key", vec![2, 3, 0, 1], ConfigEntryOperationKind::Insert, 0)], + vec![("key", vec![0, 1], ConfigEntryOperationKind::Override, None)], + vec![("key", vec![2, 3], ConfigEntryOperationKind::Insert, Some(0))], + vec![( + "key", + vec![2, 3, 0, 1], + ConfigEntryOperationKind::Insert, + Some(0), + )], ), ( - vec![("key", vec![0, 1], ConfigEntryOperationKind::Override, -1)], - vec![("key", vec![2, 3], ConfigEntryOperationKind::Insert, 1)], - vec![("key", vec![0, 2, 3, 1], ConfigEntryOperationKind::Insert, 1)], + vec![("key", vec![0, 1], ConfigEntryOperationKind::Override, None)], + vec![("key", vec![2, 3], ConfigEntryOperationKind::Insert, Some(1))], + vec![( + "key", + vec![0, 2, 3, 1], + ConfigEntryOperationKind::Insert, + Some(1), + )], ), ]; for (left_entries, right_entries, expected) in cases { let mut left_value = ValueRef::dict(None); let mut right_value = ValueRef::dict(None); for (key, val, op, index) in left_entries { - left_value.dict_update_entry(key, &ValueRef::list_int(val.as_slice()), &op, &index); + left_value.dict_update_entry(key, &ValueRef::list_int(val.as_slice()), &op, index); } for (key, val, op, index) in right_entries { right_value.dict_update_entry( key, &ValueRef::list_int(val.as_slice()), &op, - &index, + index.as_ref(), ); } let result = left_value.bin_bit_or(&mut ctx, &right_value); @@ -485,10 +578,10 @@ mod test_value_union { let result_dict = result.as_dict_ref(); let result_val = result_dict.values.get(key).unwrap(); let result_op = result_dict.ops.get(key).unwrap(); - let result_index = result_dict.insert_indexs.get(key).unwrap(); + let result_index = result_dict.insert_indexs.get(key); assert_eq!(result_val.clone(), ValueRef::list_int(val.as_slice())); assert_eq!(*result_op, op); - assert_eq!(*result_index, index); + assert_eq!(result_index.cloned(), index); } } } @@ -498,66 +591,66 @@ mod test_value_union { let mut ctx = Context::new(); let cases = [ ( - vec![("key1", "value", ConfigEntryOperationKind::Union, -1)], - vec![("key1", "value", ConfigEntryOperationKind::Union, -1)], - vec![("key2", "value", ConfigEntryOperationKind::Union, -1)], + vec![("key1", "value", ConfigEntryOperationKind::Union, None)], + vec![("key1", "value", ConfigEntryOperationKind::Union, None)], + vec![("key2", "value", ConfigEntryOperationKind::Union, None)], vec![ - ("key1", "value", ConfigEntryOperationKind::Union, -1), - ("key2", "value", ConfigEntryOperationKind::Union, -1), + ("key1", "value", ConfigEntryOperationKind::Union, None), + ("key2", "value", ConfigEntryOperationKind::Union, None), ], ), ( - vec![("key1", "value1", ConfigEntryOperationKind::Override, -1)], - vec![("key1", "value2", ConfigEntryOperationKind::Override, -1)], - vec![("key2", "value", ConfigEntryOperationKind::Override, -1)], + vec![("key1", "value1", ConfigEntryOperationKind::Override, None)], + vec![("key1", "value2", ConfigEntryOperationKind::Override, None)], + vec![("key2", "value", ConfigEntryOperationKind::Override, None)], vec![ - ("key1", "value2", ConfigEntryOperationKind::Override, -1), - ("key2", "value", ConfigEntryOperationKind::Override, -1), + ("key1", "value2", ConfigEntryOperationKind::Override, None), + ("key2", "value", ConfigEntryOperationKind::Override, None), ], ), ( - vec![("key1", "value1", ConfigEntryOperationKind::Union, -1)], - vec![("key1", "value2", ConfigEntryOperationKind::Override, -1)], - vec![("key2", "value", ConfigEntryOperationKind::Override, -1)], + vec![("key1", "value1", ConfigEntryOperationKind::Union, None)], + vec![("key1", "value2", ConfigEntryOperationKind::Override, None)], + vec![("key2", "value", ConfigEntryOperationKind::Override, None)], vec![ - ("key1", "value2", ConfigEntryOperationKind::Override, -1), - ("key2", "value", ConfigEntryOperationKind::Override, -1), + ("key1", "value2", ConfigEntryOperationKind::Override, None), + ("key2", "value", ConfigEntryOperationKind::Override, None), ], ), ( vec![ - ("key1", "value1", ConfigEntryOperationKind::Union, -1), - ("key2", "value2", ConfigEntryOperationKind::Union, -1), + ("key1", "value1", ConfigEntryOperationKind::Union, None), + ("key2", "value2", ConfigEntryOperationKind::Union, None), ], vec![ ( "key1", "override_value1", ConfigEntryOperationKind::Override, - -1, + None, ), ( "key2", "override_value2", ConfigEntryOperationKind::Override, - -1, + None, ), ], - vec![("key3", "value", ConfigEntryOperationKind::Union, -1)], + vec![("key3", "value", ConfigEntryOperationKind::Union, None)], vec![ ( "key1", "override_value1", ConfigEntryOperationKind::Override, - -1, + None, ), ( "key2", "override_value2", ConfigEntryOperationKind::Override, - -1, + None, ), - ("key3", "value", ConfigEntryOperationKind::Union, -1), + ("key3", "value", ConfigEntryOperationKind::Union, None), ], ), ]; @@ -565,25 +658,25 @@ mod test_value_union { let mut left_value = ValueRef::dict(None); let mut right_value = ValueRef::dict(None); for (key, val, op, index) in left_entries { - left_value.dict_update_entry(key, &ValueRef::str(val), &op, &index); + left_value.dict_update_entry(key, &ValueRef::str(val), &op, index); } for (key, val, op, index) in right_entries { - right_value.dict_update_entry(key, &ValueRef::str(val), &op, &index); + right_value.dict_update_entry(key, &ValueRef::str(val), &op, index); } for (key, val, op, index) in both_entries { let both_val = ValueRef::str(val); - left_value.dict_update_entry(key, &both_val, &op, &index); - left_value.dict_update_entry(key, &both_val, &op, &index); + left_value.dict_update_entry(key, &both_val, &op, index); + left_value.dict_update_entry(key, &both_val, &op, index); } let result = left_value.bin_bit_or(&mut ctx, &right_value); for (key, val, op, index) in expected { let result_dict = result.as_dict_ref(); let result_val = result_dict.values.get(key).unwrap().as_str(); let result_op = result_dict.ops.get(key).unwrap(); - let result_index = result_dict.insert_indexs.get(key).unwrap(); + let result_index = result_dict.insert_indexs.get(key); assert_eq!(result_val, val); assert_eq!(*result_op, op); - assert_eq!(*result_index, index); + assert_eq!(result_index, index); } } } diff --git a/kclvm/sema/src/pre_process/config.rs b/kclvm/sema/src/pre_process/config.rs index d5668fd7d..fbdd099b2 100644 --- a/kclvm/sema/src/pre_process/config.rs +++ b/kclvm/sema/src/pre_process/config.rs @@ -60,7 +60,6 @@ impl ConfigNestAttrTransformer { } else { ast::ConfigEntryOperation::Union }, - insert_index: -1, }; let config_expr = ast::ConfigExpr { items: vec![Box::new(ast::Node::new( diff --git a/kclvm/sema/src/resolver/config.rs b/kclvm/sema/src/resolver/config.rs index 948cfb9ca..59893f0ff 100644 --- a/kclvm/sema/src/resolver/config.rs +++ b/kclvm/sema/src/resolver/config.rs @@ -546,7 +546,6 @@ impl<'ctx> Resolver<'ctx> { let mut stack_depth: usize = 0; let value_ty = self.check_config_entry(key, value); stack_depth += self.switch_config_expr_context_by_key(key); - let mut has_insert_index = false; let val_ty = match key { Some(key) => match &key.node { ast::Expr::Identifier(identifier) => { @@ -601,7 +600,6 @@ impl<'ctx> Resolver<'ctx> { ast::Expr::Subscript(subscript) if matches!(subscript.value.node, ast::Expr::Identifier(_)) => { - has_insert_index = true; let val_ty = value_ty.unwrap_or(self.expr(value)); key_types.push(self.str_ty()); val_types.push(Type::list_ref(val_ty.clone())); @@ -687,7 +685,6 @@ impl<'ctx> Resolver<'ctx> { } }; if matches!(op, ast::ConfigEntryOperation::Insert) - && !has_insert_index && !val_ty.is_any() && !val_ty.is_list() { diff --git a/kclvm/tools/src/vet/expr_builder.rs b/kclvm/tools/src/vet/expr_builder.rs index db34a1d76..11853c478 100644 --- a/kclvm/tools/src/vet/expr_builder.rs +++ b/kclvm/tools/src/vet/expr_builder.rs @@ -153,7 +153,6 @@ impl ExprGenerator for ExprBuilder { key: Some(k), value: v, operation: ConfigEntryOperation::Union, - insert_index: -1 }); config_entries.push(config_entry); } @@ -293,7 +292,6 @@ impl ExprGenerator for ExprBuilder { key: Some(k), value: v, operation: ConfigEntryOperation::Union, - insert_index: -1 }, loc.clone() ); @@ -462,7 +460,6 @@ impl ExprGenerator> for E )), value: v, operation: ConfigEntryOperation::Union, - insert_index: -1 }, loc.clone() ); @@ -602,7 +599,6 @@ impl ExprGenerator for ExprBuilder { key: Some(node_ref!(Expr::StringLit(k))), value: v, operation: ConfigEntryOperation::Union, - insert_index: -1 }); config_entries.push(config_entry); } diff --git a/test/grammar/attr_operator/list_index/insert/insert_0/main.k b/test/grammar/attr_operator/list_index/insert/insert_0/main.k new file mode 100644 index 000000000..4286eb98b --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_0/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[1] += [2] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_0/stdout.golden b/test/grammar/attr_operator/list_index/insert/insert_0/stdout.golden new file mode 100644 index 000000000..0d261b25f --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_0/stdout.golden @@ -0,0 +1,6 @@ +a: + arr: + - 1 + - 2 + - 1 + - 1 diff --git a/test/grammar/attr_operator/list_index/insert/insert_1/main.k b/test/grammar/attr_operator/list_index/insert/insert_1/main.k new file mode 100644 index 000000000..8170e44a7 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_1/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[1] += [2] + [2] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_1/stdout.golden b/test/grammar/attr_operator/list_index/insert/insert_1/stdout.golden new file mode 100644 index 000000000..19de7b5fe --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_1/stdout.golden @@ -0,0 +1,7 @@ +a: + arr: + - 1 + - 2 + - 2 + - 1 + - 1 diff --git a/test/grammar/attr_operator/list_index/insert/insert_2/main.k b/test/grammar/attr_operator/list_index/insert/insert_2/main.k new file mode 100644 index 000000000..5edd79cfb --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_2/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[-2] += [0] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_2/stdout.golden b/test/grammar/attr_operator/list_index/insert/insert_2/stdout.golden new file mode 100644 index 000000000..e20ce8096 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_2/stdout.golden @@ -0,0 +1,6 @@ +a: + arr: + - 1 + - 0 + - 1 + - 1 diff --git a/test/grammar/attr_operator/list_index/insert/insert_3/main.k b/test/grammar/attr_operator/list_index/insert/insert_3/main.k new file mode 100644 index 000000000..a87474510 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_3/main.k @@ -0,0 +1,3 @@ +a = { + arr[0] += [0] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_3/stdout.golden b/test/grammar/attr_operator/list_index/insert/insert_3/stdout.golden new file mode 100644 index 000000000..44c7927ba --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_3/stdout.golden @@ -0,0 +1,3 @@ +a: + arr: + - 0 diff --git a/test/grammar/attr_operator/list_index/insert/insert_fail_0/main.k b/test/grammar/attr_operator/list_index/insert/insert_fail_0/main.k new file mode 100644 index 000000000..3275bbe24 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_fail_0/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[5] += [2] + [2] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_fail_0/stderr.golden b/test/grammar/attr_operator/list_index/insert/insert_fail_0/stderr.golden new file mode 100644 index 000000000..30ebe13b4 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_fail_0/stderr.golden @@ -0,0 +1 @@ +insertion index (is 5) should be <= len (is 3) \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/insert/insert_fail_1/main.k b/test/grammar/attr_operator/list_index/insert/insert_fail_1/main.k new file mode 100644 index 000000000..cbaa8af12 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_fail_1/main.k @@ -0,0 +1,3 @@ +a = { + arr[1] += [0] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_fail_1/stderr.golden b/test/grammar/attr_operator/list_index/insert/insert_fail_1/stderr.golden new file mode 100644 index 000000000..4f41fc469 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_fail_1/stderr.golden @@ -0,0 +1 @@ +insertion index (is 1) should be <= len (is 0) \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/insert/insert_fail_2/main.k b/test/grammar/attr_operator/list_index/insert/insert_fail_2/main.k new file mode 100644 index 000000000..1bf5d7420 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_fail_2/main.k @@ -0,0 +1,3 @@ +a = { + arr[-1] += [0] +} diff --git a/test/grammar/attr_operator/list_index/insert/insert_fail_2/stderr.golden b/test/grammar/attr_operator/list_index/insert/insert_fail_2/stderr.golden new file mode 100644 index 000000000..07a23d066 --- /dev/null +++ b/test/grammar/attr_operator/list_index/insert/insert_fail_2/stderr.golden @@ -0,0 +1 @@ +index out of bounds \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/override/override_0/main.k b/test/grammar/attr_operator/list_index/override/override_0/main.k new file mode 100644 index 000000000..5c95b50de --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_0/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[1] = 2 +} diff --git a/test/grammar/attr_operator/list_index/override/override_0/stdout.golden b/test/grammar/attr_operator/list_index/override/override_0/stdout.golden new file mode 100644 index 000000000..1193c129f --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_0/stdout.golden @@ -0,0 +1,5 @@ +a: + arr: + - 1 + - 2 + - 1 diff --git a/test/grammar/attr_operator/list_index/override/override_1/main.k b/test/grammar/attr_operator/list_index/override/override_1/main.k new file mode 100644 index 000000000..ba27ae6c9 --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_1/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[-2] = 2 +} diff --git a/test/grammar/attr_operator/list_index/override/override_1/stdout.golden b/test/grammar/attr_operator/list_index/override/override_1/stdout.golden new file mode 100644 index 000000000..1193c129f --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_1/stdout.golden @@ -0,0 +1,5 @@ +a: + arr: + - 1 + - 2 + - 1 diff --git a/test/grammar/attr_operator/list_index/override/override_fail_0/main.k b/test/grammar/attr_operator/list_index/override/override_fail_0/main.k new file mode 100644 index 000000000..27630d690 --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_fail_0/main.k @@ -0,0 +1,4 @@ +a = { + arr = [1, 1, 1] + arr[5] = 2 +} diff --git a/test/grammar/attr_operator/list_index/override/override_fail_0/stderr.golden b/test/grammar/attr_operator/list_index/override/override_fail_0/stderr.golden new file mode 100644 index 000000000..068284a93 --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_fail_0/stderr.golden @@ -0,0 +1 @@ +index out of bounds: the len is 3 but the index is 5 \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/override/override_fail_1/main.k b/test/grammar/attr_operator/list_index/override/override_fail_1/main.k new file mode 100644 index 000000000..c81bf0cea --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_fail_1/main.k @@ -0,0 +1,3 @@ +a = { + arr[1] = [0] +} diff --git a/test/grammar/attr_operator/list_index/override/override_fail_1/stderr.golden b/test/grammar/attr_operator/list_index/override/override_fail_1/stderr.golden new file mode 100644 index 000000000..441481ac9 --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_fail_1/stderr.golden @@ -0,0 +1 @@ +only list attribute can be override value with the index 1 \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/override/override_fail_2/main.k b/test/grammar/attr_operator/list_index/override/override_fail_2/main.k new file mode 100644 index 000000000..c1bf38eea --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_fail_2/main.k @@ -0,0 +1,4 @@ +b = { + arr = [{name = "One"}, {name="asdad"}] + arr[5] = {name = "Two"} +} \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/override/override_fail_2/stderr.golden b/test/grammar/attr_operator/list_index/override/override_fail_2/stderr.golden new file mode 100644 index 000000000..bbd37dd15 --- /dev/null +++ b/test/grammar/attr_operator/list_index/override/override_fail_2/stderr.golden @@ -0,0 +1 @@ +index out of bounds: the len is 2 but the index is 5 \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/unification/unification_0/main.k b/test/grammar/attr_operator/list_index/unification/unification_0/main.k new file mode 100644 index 000000000..806bc153b --- /dev/null +++ b/test/grammar/attr_operator/list_index/unification/unification_0/main.k @@ -0,0 +1,4 @@ +a = { + config = [{name = "One"}, {name = "asdad"}] + config[0]: {name = "Two"} +} \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/unification/unification_0/stdout.golden b/test/grammar/attr_operator/list_index/unification/unification_0/stdout.golden new file mode 100644 index 000000000..6851678eb --- /dev/null +++ b/test/grammar/attr_operator/list_index/unification/unification_0/stdout.golden @@ -0,0 +1,4 @@ +a: + config: + - name: Two + - name: asdad diff --git a/test/grammar/attr_operator/list_index/unification/unification_1/main.k b/test/grammar/attr_operator/list_index/unification/unification_1/main.k new file mode 100644 index 000000000..73a01b8a9 --- /dev/null +++ b/test/grammar/attr_operator/list_index/unification/unification_1/main.k @@ -0,0 +1,4 @@ +a = { + config = [{name = "One"}, {name = "asdad"}] + config[0]: {key = "value"} +} \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/unification/unification_1/stdout.golden b/test/grammar/attr_operator/list_index/unification/unification_1/stdout.golden new file mode 100644 index 000000000..5438366e4 --- /dev/null +++ b/test/grammar/attr_operator/list_index/unification/unification_1/stdout.golden @@ -0,0 +1,5 @@ +a: + config: + - name: One + key: value + - name: asdad diff --git a/test/grammar/attr_operator/list_index/unification/unification_fail_0/main.k b/test/grammar/attr_operator/list_index/unification/unification_fail_0/main.k new file mode 100644 index 000000000..5eb61d039 --- /dev/null +++ b/test/grammar/attr_operator/list_index/unification/unification_fail_0/main.k @@ -0,0 +1,4 @@ +a = { + config = [{name = "One"}, {name = "asdad"}] + config[0]: {name: "value"} +} \ No newline at end of file diff --git a/test/grammar/attr_operator/list_index/unification/unification_fail_0/stderr.golden b/test/grammar/attr_operator/list_index/unification/unification_fail_0/stderr.golden new file mode 100644 index 000000000..06f9922dc --- /dev/null +++ b/test/grammar/attr_operator/list_index/unification/unification_fail_0/stderr.golden @@ -0,0 +1 @@ +conflicting values on the attribute 'name' \ No newline at end of file diff --git a/test/grammar/schema/config_op/delete/delete_0/main.k b/test/grammar/schema/config_op/delete/delete_0/main.k index 77b9de075..44ab3e558 100644 --- a/test/grammar/schema/config_op/delete/delete_0/main.k +++ b/test/grammar/schema/config_op/delete/delete_0/main.k @@ -4,5 +4,8 @@ schema Person: person = Person { info = {"key2": "value2"} - hc[0] = None +} +personDeleteHc0 = { + **person + hc[0] = Undefined } diff --git a/test/grammar/schema/config_op/delete/delete_0/stdout.golden b/test/grammar/schema/config_op/delete/delete_0/stdout.golden index 5d7086c6e..2e9e2cafa 100644 --- a/test/grammar/schema/config_op/delete/delete_0/stdout.golden +++ b/test/grammar/schema/config_op/delete/delete_0/stdout.golden @@ -1,4 +1,11 @@ person: + info: + key2: value2 + hc: + - 1 + - 2 + - 3 +personDeleteHc0: info: key2: value2 hc: