diff --git a/kclvm/query/src/override.rs b/kclvm/query/src/override.rs index 51c63b478..b080e5cf2 100644 --- a/kclvm/query/src/override.rs +++ b/kclvm/query/src/override.rs @@ -297,6 +297,85 @@ fn apply_import_paths_on_module(m: &mut ast::Module, import_paths: &[String]) -> Ok(()) } +macro_rules! override_top_level_stmt { + ($self:expr, $stmt: expr) => { + let item = $stmt.value.clone(); + let mut value = $self.clone_override_value(); + // Use position information that needs to override the expression. + value.set_pos(item.pos()); + match &$self.operation { + ast::ConfigEntryOperation::Union => { + if let ast::Expr::Config(insert_config_expr) = &value.node { + match &mut $stmt.value.node { + ast::Expr::Schema(schema_expr) => { + if let ast::Expr::Config(config_expr) = &mut schema_expr.config.node { + for item in &insert_config_expr.items { + let parts = get_key_parts(&item.node.key); + // Deal double star and config if expr + if parts.is_empty() { + config_expr.items.push(item.clone()); + $self.has_override = true; + } else { + if replace_config_with_path_parts( + config_expr, + &parts, + &$self.action, + &item.node.operation, + &Some(item.node.value.clone()), + ) { + $self.has_override = true; + } + } + } + } + } + ast::Expr::Config(config_expr) => { + for item in &insert_config_expr.items { + let parts = get_key_parts(&item.node.key); + // Deal double star and config if expr + if parts.is_empty() { + config_expr.items.push(item.clone()); + $self.has_override = true; + } else { + if replace_config_with_path_parts( + config_expr, + &parts, + &$self.action, + &item.node.operation, + &Some(item.node.value.clone()), + ) { + $self.has_override = true; + } + } + } + } + _ => {} + } + } else { + // Override the node value. + $stmt.value = value; + $self.has_override = true; + } + } + ast::ConfigEntryOperation::Insert => { + if let ast::Expr::List(insert_list_expr) = &value.node { + if let ast::Expr::List(list_expr) = &mut $stmt.value.node { + for value in &insert_list_expr.elts { + list_expr.elts.push(value.clone()); + } + $self.has_override = true; + } + } + } + ast::ConfigEntryOperation::Override => { + // Override the node value. + $stmt.value = value; + $self.has_override = true; + } + } + }; +} + /// OverrideTransformer is used to walk AST and transform it with the override values. struct OverrideTransformer { pub target_id: String, @@ -326,18 +405,18 @@ impl<'ctx> MutSelfMutWalker<'ctx> for OverrideTransformer { let target = assign_stmt.targets.get(0).unwrap().node.clone(); let target = get_target_path(&target); if target == self.target_id { - let item = assign_stmt.value.clone(); - - let mut value = self.clone_override_value(); - // Use position information that needs to override the expression. - value.set_pos(item.pos()); - // Override the node value. - assign_stmt.value = value; - self.has_override = true; + override_top_level_stmt!(self, assign_stmt); } } - } - if let ast::Stmt::Unification(unification_stmt) = &mut stmt.node { + } else if let ast::Stmt::AugAssign(aug_assign_stmt) = &mut stmt.node { + if self.field_paths.len() == 0 { + let target = aug_assign_stmt.target.node.clone(); + let target = get_target_path(&target); + if target == self.target_id { + override_top_level_stmt!(self, aug_assign_stmt); + } + } + } else if let ast::Stmt::Unification(unification_stmt) = &mut stmt.node { let target = match unification_stmt.target.node.names.get(0) { Some(name) => name, None => bug!( @@ -347,17 +426,55 @@ impl<'ctx> MutSelfMutWalker<'ctx> for OverrideTransformer { }; if target.node == self.target_id { let item = unification_stmt.value.clone(); - let mut value = self.clone_override_value(); // Use position information that needs to override the expression. value.set_pos(item.pos()); - - // Unification is only support to override the schema expression. - if let ast::Expr::Schema(schema_expr) = value.node { - if self.field_paths.len() == 0 { - self.has_override = true; - unification_stmt.value = - Box::new(ast::Node::dummy_node(schema_expr)); + match &self.operation { + ast::ConfigEntryOperation::Union => { + if let ast::Expr::Config(insert_config_expr) = &value.node { + if let ast::Expr::Config(config_expr) = + &mut unification_stmt.value.node.config.node + { + for item in &insert_config_expr.items { + let parts = get_key_parts(&item.node.key); + // Deal double star and config if expr + if parts.is_empty() { + config_expr.items.push(item.clone()); + self.has_override = true; + } else { + if replace_config_with_path_parts( + config_expr, + &parts, + &self.action, + &item.node.operation, + &Some(item.node.value.clone()), + ) { + self.has_override = true; + } + } + } + } + } else { + // Unification is only support to override the schema expression. + if let ast::Expr::Schema(schema_expr) = value.node { + if self.field_paths.len() == 0 { + unification_stmt.value = + Box::new(ast::Node::dummy_node(schema_expr)); + self.has_override = true; + } + } + } + } + ast::ConfigEntryOperation::Insert + | ast::ConfigEntryOperation::Override => { + // Unification is only support to override the schema expression. + if let ast::Expr::Schema(schema_expr) = value.node { + if self.field_paths.len() == 0 { + unification_stmt.value = + Box::new(ast::Node::dummy_node(schema_expr)); + self.has_override = true; + } + } } } } diff --git a/kclvm/query/src/tests.rs b/kclvm/query/src/tests.rs index c7ecd0350..a6647f6e8 100644 --- a/kclvm/query/src/tests.rs +++ b/kclvm/query/src/tests.rs @@ -114,12 +114,18 @@ fn test_override_file_config() { "appConfigurationUnification.overQuota=False".to_string(), "appConfigurationUnification.resource.cpu-".to_string(), "appConfigurationUnification.svc=s.Service {}".to_string(), - "config.x:1".to_string(), + "appConfigurationUnification:{name=\"name\"}".to_string(), + "config.x:{a:1}".to_string(), + "config.x:{b:2}".to_string(), + "config.x:{b:3}".to_string(), + "config.x:{c.d:4}".to_string(), "config.y=1".to_string(), "config.z+=[1,2,3]".to_string(), + "config.z+=[4,5,6]".to_string(), "var1:1".to_string(), "var2=1".to_string(), "var3+=[1,2,3]".to_string(), + "var3+=[4,5,6]".to_string(), "var4:AppConfiguration {image:'image'}".to_string(), ]; let import_paths = vec!["service as s".to_string()]; @@ -187,11 +193,12 @@ appConfigurationUnification: AppConfiguration { mainContainer: Main {name: "override_name"} overQuota: False svc = s.Service {} + name = "name" } -config = {x: 1, y = 1, z += [1, 2, 3]} +config = {x: {a: 1, b: 3, c: {d: 4}}, y = 1, z += [1, 2, 3, 4, 5, 6]} var1 = 1 var2 = 1 -var3 += [1, 2, 3] +var3 += [1, 2, 3, 4, 5, 6] var4: AppConfiguration {image: 'image'} "# );