1use std::collections::{BTreeSet, HashMap, HashSet};
63use std::fmt::Display;
64
65use kconfig_parser::{
66 ast::{structs::Expr, Dependency, Element},
67 Symbol,
68};
69
70use crate::{Item, ItemReference};
71
72#[derive(Clone, Debug, Eq, PartialEq, Hash)]
73pub struct ForwardDependency {
74 forward_name: String,
75 maybe_condition: Option<Dependency>,
76}
77
78#[derive(Clone, Debug, Eq, PartialEq, Hash)]
79pub struct BackwardDependency {
80 backward_name: String,
81 maybe_condition: Option<Dependency>,
82}
83
84#[derive(Debug)]
85pub(crate) struct SelectAndImplyDependencyResolver {
86 forward_select: HashMap<String, HashSet<ForwardDependency>>,
87 backward_select: HashMap<String, HashSet<BackwardDependency>>,
88 forward_imply: HashMap<String, HashSet<ForwardDependency>>,
89 backward_imply: HashMap<String, HashSet<BackwardDependency>>,
90}
91
92impl SelectAndImplyDependencyResolver {
93 pub(crate) fn new() -> Self {
94 Self {
95 forward_select: HashMap::new(),
96 backward_select: HashMap::new(),
97 forward_imply: HashMap::new(),
98 backward_imply: HashMap::new(),
99 }
100 }
101
102 pub(crate) fn put_select(
103 &mut self,
104 itemref: &ItemReference,
105 selected_name: &str,
106 maybe_condition: &Option<Dependency>,
107 ) {
108 let forward_dependency = ForwardDependency {
109 forward_name: selected_name.to_string(),
110 maybe_condition: maybe_condition.clone(),
111 };
112 match self.forward_select.get_mut(&itemref.to_string()) {
113 Some(value) => {
114 value.insert(forward_dependency);
115 }
116 None => {
117 let mut set = HashSet::new();
118 set.insert(forward_dependency);
119 self.forward_select.insert(itemref.to_string(), set);
120 }
121 }
122
123 let backward_dependency = BackwardDependency {
124 backward_name: itemref.to_string(),
125 maybe_condition: maybe_condition.clone(),
126 };
127 match self.backward_select.get_mut(&selected_name.to_string()) {
128 Some(value) => {
129 value.insert(backward_dependency);
130 }
131 None => {
132 let mut set = HashSet::new();
133 set.insert(backward_dependency);
134 self.backward_select.insert(selected_name.to_string(), set);
135 }
136 }
137 }
138
139 pub(crate) fn put_imply(
140 &mut self,
141 itemref: &ItemReference,
142 implied_name: &str,
143 maybe_condition: &Option<Dependency>,
144 ) {
145 let forward_dependency = ForwardDependency {
146 forward_name: implied_name.to_string(),
147 maybe_condition: maybe_condition.clone(),
148 };
149 match self.forward_imply.get_mut(&itemref.to_string()) {
150 Some(value) => {
151 value.insert(forward_dependency);
152 }
153 None => {
154 let mut set = HashSet::new();
155 set.insert(forward_dependency);
156 self.forward_imply.insert(itemref.to_string(), set);
157 }
158 }
159 let backward_dependency = BackwardDependency {
160 backward_name: itemref.to_string(),
161 maybe_condition: maybe_condition.clone(),
162 };
163 match self.backward_imply.get_mut(&implied_name.to_string()) {
164 Some(value) => {
165 value.insert(backward_dependency);
166 }
167 None => {
168 let mut set = HashSet::new();
169 set.insert(backward_dependency);
170 self.backward_imply.insert(implied_name.to_string(), set);
171 }
172 }
173 }
174}
175
176#[derive(Debug)]
181pub(crate) struct DependencyResolver {
182 select_and_imply_resolver: SelectAndImplyDependencyResolver,
183 macro_symbols: HashSet<Symbol>,
184}
185
186impl DependencyResolver {
187 pub(crate) fn new(
191 select_and_imply_resolver: SelectAndImplyDependencyResolver,
192 macro_symbols: HashSet<Symbol>,
193 ) -> Self {
194 Self {
195 select_and_imply_resolver,
196 macro_symbols,
197 }
198 }
199
200 pub(crate) fn resolve(&mut self, items: &mut HashMap<ItemReference, Item>) {
201 let mut lut: HashMap<String, ItemReference> = items
204 .iter()
205 .map(|(k, _)| (k.to_string(), k.clone()))
206 .collect();
207
208 let itemrefs: HashSet<ItemReference> = items.keys().cloned().collect();
209
210 for (_, item) in items.iter_mut() {
211 if let Some(elt) = item.raw_elt() {
212 let item_types = elt.types().cloned();
213 let maybe_defaults = elt.defaults().cloned();
214 let itemref = &item.itemref();
215 item.set_dependencies(self.resolve_dependencies(elt, &item, &itemrefs, &mut lut));
216 item.set_selects_me(self.resolve_select(&itemref, &itemrefs, &mut lut));
217 item.set_imply_me(self.resolve_imply(&itemref, &itemrefs, &mut lut));
218 item.set_selected(self.resolve_selected(&itemref, &itemrefs, &mut lut));
219 item.set_implied(self.resolve_implied(&itemref, &itemrefs, &mut lut));
220 self.resolve_config_dependencies(item_types, item, &itemrefs, &mut lut);
221 self.resolve_default_expressions(maybe_defaults, &itemrefs, &mut lut, item);
222 }
223 }
224 }
225
226 fn resolve_dependencies(
227 &self,
228 elt: &Element,
229 item: &Item,
230 itemrefs: &HashSet<ItemReference>,
231 lut: &mut HashMap<String, ItemReference>,
232 ) -> HashSet<ItemDependency> {
233 let mut set: HashSet<ItemDependency> = HashSet::new();
234
235 if let Some(parent) = item.parent() {
236 set.insert(ItemDependency::Heavy(ResolvedExpr::new(
237 &Expr::Sym(parent.clone()),
238 itemrefs,
239 &self.macro_symbols,
240 lut,
241 )));
242 }
243
244 let dependencies: HashSet<ItemDependency> = elt
245 .dependencies()
246 .iter()
247 .map(|d| d.expr())
248 .map(|e| ResolvedExpr::new(&e, itemrefs, &self.macro_symbols, lut))
249 .map(|re| ItemDependency::Normal(re))
250 .collect();
251
252 let conditions: HashSet<ItemDependency> = item
253 .conditions()
254 .iter()
255 .map(|d| d.expr())
256 .map(|e| ResolvedExpr::new(&e, itemrefs, &self.macro_symbols, lut))
257 .map(|re| ItemDependency::Trivial(re))
258 .collect();
259
260 set.extend(dependencies);
261 set.extend(conditions);
262
263 set
264 }
265
266 fn resolve_select(
267 &self,
268 itemref: &ItemReference,
269 itemrefs: &HashSet<ItemReference>,
270 lut: &mut HashMap<String, ItemReference>,
271 ) -> HashMap<String, Option<ResolvedExpr>> {
272 match self
273 .select_and_imply_resolver
274 .backward_select
275 .get(&itemref.to_string())
276 {
277 Some(s) => {
278 let mut map = HashMap::new();
279 for dep in s {
280 let name = dep.backward_name.clone();
281 match &dep.maybe_condition {
282 Some(dep) => map.insert(
283 name,
284 Some(ResolvedExpr::new(
285 &dep.expr(),
286 itemrefs,
287 &self.macro_symbols,
288 lut,
289 )),
290 ),
291 None => map.insert(name, None),
292 };
293 }
294 map
295 }
296 None => HashMap::new(),
297 }
298 }
299
300 fn resolve_selected(
301 &self,
302 itemref: &ItemReference,
303 itemrefs: &HashSet<ItemReference>,
304 lut: &mut HashMap<String, ItemReference>,
305 ) -> HashMap<String, Option<ResolvedExpr>> {
306 match self
307 .select_and_imply_resolver
308 .forward_select
309 .get(&itemref.to_string())
310 {
311 Some(s) => {
312 let mut map = HashMap::new();
313 for dep in s {
314 let name = dep.forward_name.clone();
315 match &dep.maybe_condition {
316 Some(dep) => map.insert(
317 name,
318 Some(ResolvedExpr::new(
319 &dep.expr(),
320 itemrefs,
321 &self.macro_symbols,
322 lut,
323 )),
324 ),
325 None => map.insert(name, None),
326 };
327 }
328 map
329 }
330 None => HashMap::new(),
331 }
332 }
333
334 fn resolve_imply(
335 &self,
336 itemref: &ItemReference,
337 itemrefs: &HashSet<ItemReference>,
338 lut: &mut HashMap<String, ItemReference>,
339 ) -> HashMap<String, Option<ResolvedExpr>> {
340 match self
341 .select_and_imply_resolver
342 .backward_imply
343 .get(&itemref.to_string())
344 {
345 Some(s) => {
346 let mut map = HashMap::new();
347 for dep in s {
348 let name = dep.backward_name.clone();
349 match &dep.maybe_condition {
350 Some(dep) => map.insert(
351 name,
352 Some(ResolvedExpr::new(
353 &dep.expr(),
354 itemrefs,
355 &self.macro_symbols,
356 lut,
357 )),
358 ),
359 None => map.insert(name, None),
360 };
361 }
362 map
363 }
364 None => HashMap::new(),
365 }
366 }
367
368 fn resolve_implied(
369 &self,
370 itemref: &ItemReference,
371 itemrefs: &HashSet<ItemReference>,
372 lut: &mut HashMap<String, ItemReference>,
373 ) -> HashMap<String, Option<ResolvedExpr>> {
374 match self
375 .select_and_imply_resolver
376 .forward_imply
377 .get(&itemref.to_string())
378 {
379 Some(s) => {
380 let mut map = HashMap::new();
381 for dep in s {
382 let name = dep.forward_name.clone();
383 match &dep.maybe_condition {
384 Some(dep) => map.insert(
385 name,
386 Some(ResolvedExpr::new(
387 &dep.expr(),
388 itemrefs,
389 &self.macro_symbols,
390 lut,
391 )),
392 ),
393 None => map.insert(name, None),
394 };
395 }
396 map
397 }
398 None => HashMap::new(),
399 }
400 }
401
402 fn resolve_config_dependencies(
403 &mut self,
404 item_types: Option<HashMap<kconfig_parser::ast::ConfigType, Option<Dependency>>>,
405 item: &mut Item,
406 itemrefs: &HashSet<ItemReference>,
407 lut: &mut HashMap<String, ItemReference>,
408 ) {
409 if let Some(types) = item_types {
410 for (config_type, dependency) in types {
411 if let Some(dependency) = dependency {
412 if let Some(config_item) = item.config_items_mut().get_mut(&config_type) {
413 let expr = ResolvedExpr::new(
414 &dependency.expr(),
415 itemrefs,
416 &self.macro_symbols,
417 lut,
418 );
419 config_item.set_dependencies(expr)
420 }
421 }
422 }
423 }
424 }
425
426 fn resolve_default_expressions(
427 &mut self,
428 maybe_defaults: Option<HashMap<Expr, Option<Dependency>>>,
429 itemrefs: &HashSet<ItemReference>,
430 lut: &mut HashMap<String, ItemReference>,
431 item: &mut Item,
432 ) {
433 if let Some(defaults) = maybe_defaults {
434 for (expr, maybe_dependency) in defaults {
435 let default_expr = ResolvedExpr::new(&expr, itemrefs, &self.macro_symbols, lut);
436
437 let maybe_expr = match maybe_dependency {
438 Some(dependency) => Some(ResolvedExpr::new(
439 &dependency.expr(),
440 itemrefs,
441 &self.macro_symbols,
442 lut,
443 )),
444 None => None,
445 };
446
447 for (_, config_item) in item.config_items_mut().iter_mut() {
448 config_item.add_default(
449 default_expr.clone(),
450 match &maybe_expr {
451 Some(v) => Some(v.clone()),
452 None => None,
453 },
454 );
455 }
456 }
457 }
458 }
459}
460
461#[derive(Hash, Clone, PartialEq, Eq, Debug)]
465pub struct ResolvedExpr {
466 item_expr: ItemExpr,
467 itemrefs: BTreeSet<ItemReference>,
468}
469
470impl ResolvedExpr {
471 pub fn new(
472 expr: &Expr,
473 itemrefs: &HashSet<ItemReference>,
474 macro_symbols: &HashSet<Symbol>,
475 lut: &mut HashMap<String, ItemReference>,
476 ) -> ResolvedExpr {
477 let expanded_symbols: HashMap<String, String> = macro_symbols
478 .iter()
479 .map(|s| (s.name(), s.value()))
480 .collect();
481
482 let item_expr = ItemExpr::resolve(expr, itemrefs, &expanded_symbols, lut);
483 let itemrefs = item_expr.itemrefs();
484
485 Self {
486 item_expr,
487 itemrefs: itemrefs,
488 }
489 }
490
491 pub fn item_expr<'a>(&'a self) -> &'a ItemExpr {
496 &self.item_expr
497 }
498
499 pub fn itemrefs<'a>(&'a self) -> &'a BTreeSet<ItemReference> {
501 &self.itemrefs
502 }
503}
504
505#[derive(PartialEq, Eq, Debug, Clone, PartialOrd, Ord, Hash)]
508pub enum ItemExpr {
509 Value(String),
511
512 ItemReference(ItemReference),
515
516 Eq(BTreeSet<ItemExpr>),
518
519 Ne(BTreeSet<ItemExpr>),
521
522 Lt(BTreeSet<ItemExpr>),
524
525 Gt(BTreeSet<ItemExpr>),
527
528 Lte(BTreeSet<ItemExpr>),
530
531 Gte(BTreeSet<ItemExpr>),
533
534 And(BTreeSet<ItemExpr>),
536
537 Or(BTreeSet<ItemExpr>),
539
540 Sub(Box<ItemExpr>),
542
543 Not(Box<ItemExpr>),
545
546 Unresolved(String),
548}
549impl ItemExpr {
550 fn resolve(
551 expr: &Expr,
552 refs: &HashSet<ItemReference>,
553 syms: &HashMap<String, String>,
554 cache: &mut HashMap<String, ItemReference>,
555 ) -> ItemExpr {
556 match expr {
557 Expr::Sym(s) => Self::cached_sym_to_item_expr(syms, s, cache, refs),
558 Expr::Eq(exprs) => ItemExpr::Eq(Self::expr_to_item_expr(exprs, refs, syms, cache)),
559 Expr::Ne(exprs) => ItemExpr::Ne(Self::expr_to_item_expr(exprs, refs, syms, cache)),
560 Expr::Lt(exprs) => ItemExpr::Lt(Self::expr_to_item_expr(exprs, refs, syms, cache)),
561 Expr::Gt(exprs) => ItemExpr::Gt(Self::expr_to_item_expr(exprs, refs, syms, cache)),
562 Expr::Lte(exprs) => ItemExpr::Lte(Self::expr_to_item_expr(exprs, refs, syms, cache)),
563 Expr::Gte(exprs) => ItemExpr::Gte(Self::expr_to_item_expr(exprs, refs, syms, cache)),
564 Expr::And(exprs) => ItemExpr::And(Self::expr_to_item_expr(exprs, refs, syms, cache)),
565 Expr::Or(exprs) => ItemExpr::Or(Self::expr_to_item_expr(exprs, refs, syms, cache)),
566 Expr::Sub(child) => ItemExpr::Sub(Box::new(Self::resolve(child, refs, syms, cache))),
567 Expr::Not(child) => ItemExpr::Not(Box::new(Self::resolve(child, refs, syms, cache))),
568 }
569 }
570
571 fn cached_sym_to_item_expr(
572 syms: &HashMap<String, String>,
573 s: &String,
574 cache: &mut HashMap<String, ItemReference>,
575 refs: &HashSet<ItemReference>,
576 ) -> ItemExpr {
577 if let Some(v) = syms.get(s) {
578 ItemExpr::Value(v.clone())
579 } else {
580 if let Some(v) = cache.get(s) {
581 ItemExpr::ItemReference(v.clone())
582 } else {
583 if let Some(v) = refs.get(&ItemReference::Menu(s.clone())) {
584 cache.insert(s.clone(), v.clone());
585 ItemExpr::ItemReference(v.clone())
586 } else {
587 if let Some(v) = refs.get(&ItemReference::MenuConfig(s.clone())) {
588 cache.insert(s.clone(), v.clone());
589 ItemExpr::ItemReference(v.clone())
590 } else {
591 if let Some(v) = refs.get(&ItemReference::Config(s.clone())) {
592 cache.insert(s.clone(), v.clone());
593 ItemExpr::ItemReference(v.clone())
594 } else {
595 ItemExpr::Unresolved(s.clone())
596 }
597 }
598 }
599 }
600 }
601 }
602
603 fn expr_to_item_expr(
604 exprs: &BTreeSet<Expr>,
605 refs: &HashSet<ItemReference>,
606 syms: &HashMap<String, String>,
607 cache: &mut HashMap<String, ItemReference>,
608 ) -> BTreeSet<ItemExpr> {
609 exprs
610 .iter()
611 .map(|e| Self::resolve(e, refs, syms, cache))
612 .collect()
613 }
614
615 fn itemrefs(&self) -> BTreeSet<ItemReference> {
616 let mut set: BTreeSet<ItemReference> = BTreeSet::new();
617
618 match self {
619 ItemExpr::Value(_) | ItemExpr::Unresolved(_) => set,
620 ItemExpr::ItemReference(itemref) => {
621 set.insert(itemref.clone());
622 set
623 }
624 ItemExpr::Eq(exprs)
625 | ItemExpr::Ne(exprs)
626 | ItemExpr::Lt(exprs)
627 | ItemExpr::Gt(exprs)
628 | ItemExpr::Lte(exprs)
629 | ItemExpr::Gte(exprs)
630 | ItemExpr::And(exprs)
631 | ItemExpr::Or(exprs) => {
632 for r in exprs.iter().map(|s| s.itemrefs()) {
633 set.extend(r)
634 }
635 set
636 }
637 ItemExpr::Sub(expr) | ItemExpr::Not(expr) => {
638 set.extend(expr.itemrefs());
639 set
640 }
641 }
642 }
643}
644
645impl Display for ItemExpr {
646 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
647 match self {
648 Self::Value(s) => f.write_str(s)?,
649 Self::ItemReference(itemref) => {
650 f.write_str("&")?;
651 match itemref {
652 ItemReference::Config(s) => {
653 f.write_str("config => ")?;
654 f.write_str(s)?
655 }
656 ItemReference::Menu(s) => {
657 f.write_str("menu => ")?;
658 f.write_str(s)?
659 }
660 ItemReference::MenuConfig(s) => {
661 f.write_str("menuconfig => ")?;
662 f.write_str(s)?
663 }
664 }
665 }
666
667 Self::Eq(exprs) => {
668 f.write_str("eq {")?;
669 for expr in exprs {
670 expr.fmt(f)?;
671 }
672 f.write_str("}")?;
673 }
674
675 Self::Ne(exprs) => {
676 f.write_str("ne {")?;
677 for expr in exprs {
678 expr.fmt(f)?;
679 }
680 f.write_str("}")?;
681 }
682
683 Self::Lt(exprs) => {
684 f.write_str("lt {")?;
685 for expr in exprs {
686 expr.fmt(f)?;
687 }
688 f.write_str("}")?;
689 }
690
691 Self::Gt(exprs) => {
692 f.write_str("gt {")?;
693 for expr in exprs {
694 expr.fmt(f)?;
695 }
696 f.write_str("}")?;
697 }
698
699 Self::Lte(exprs) => {
700 f.write_str("lte {")?;
701 for expr in exprs {
702 expr.fmt(f)?;
703 }
704 f.write_str("}")?;
705 }
706
707 Self::Gte(exprs) => {
708 f.write_str("gte {")?;
709 for expr in exprs {
710 expr.fmt(f)?;
711 }
712 f.write_str("}")?;
713 }
714
715 Self::And(exprs) => {
716 f.write_str("and {")?;
717 for expr in exprs {
718 expr.fmt(f)?;
719 }
720 f.write_str("}")?;
721 }
722
723 Self::Or(exprs) => {
724 f.write_str("or {")?;
725 for expr in exprs {
726 expr.fmt(f)?;
727 }
728 f.write_str("}")?;
729 }
730
731 Self::Sub(expr) => {
732 f.write_str("(")?;
733 expr.fmt(f)?;
734 f.write_str(")")?;
735 }
736
737 Self::Not(expr) => {
738 f.write_str("not (")?;
739 expr.fmt(f)?;
740 f.write_str(")")?;
741 }
742
743 Self::Unresolved(s) => {
744 f.write_str("#")?;
745 f.write_str(s)?
746 }
747 };
748
749 Ok(())
750 }
751}
752
753#[derive(Clone, Eq, PartialEq, Debug, Hash)]
754pub enum ItemDependency {
755 Heavy(ResolvedExpr),
756 Normal(ResolvedExpr),
757 Trivial(ResolvedExpr),
758}
759
760impl ItemDependency {
761 pub fn expr<'a>(&'a self) -> &'a ResolvedExpr {
762 match self {
763 ItemDependency::Heavy(expr)
764 | ItemDependency::Normal(expr)
765 | ItemDependency::Trivial(expr) => expr,
766 }
767 }
768}