diff options
| -rw-r--r-- | kconfiglib.py | 106 | ||||
| -rw-r--r-- | tests/Kbounds | 33 | ||||
| -rw-r--r-- | tests/Kchain | 49 | ||||
| -rw-r--r-- | tests/Kdep | 18 | ||||
| -rw-r--r-- | tests/Klocation_included | 2 | ||||
| -rw-r--r-- | tests/Kref | 2 | ||||
| -rw-r--r-- | tests/Ktext | 6 | ||||
| -rw-r--r-- | testsuite.py | 84 |
8 files changed, 239 insertions, 61 deletions
diff --git a/kconfiglib.py b/kconfiglib.py index 9eb7680..298a61c 100644 --- a/kconfiglib.py +++ b/kconfiglib.py @@ -821,12 +821,13 @@ class Config(object): if tokens.check(T_IF) else None) # In case the symbol is defined in multiple locations, we need to - # remember what prompts, defaults, and selects are new for this - # definition, as "depends on" should only apply to the local + # remember what prompts, defaults, selects, and implies are new for + # this definition, as "depends on" should only apply to the local # definition. new_prompt = None new_def_exprs = [] new_selects = [] + new_implies = [] # Dependencies from 'depends on' statements depends_on_expr = None @@ -903,6 +904,17 @@ class Config(object): self._parse_expr(tokens, stmt, line, filename, linenr) if tokens.check(T_IF) else None)) + elif t0 == T_IMPLY: + target = tokens.get_next() + + stmt.referenced_syms.add(target) + stmt.implied_syms.add(target) + + new_implies.append( + (target, + self._parse_expr(tokens, stmt, line, filename, linenr) + if tokens.check(T_IF) else None)) + elif t0 in (T_BOOL, T_TRISTATE, T_INT, T_HEX, T_STRING): stmt.type = TOKEN_TO_TYPE[t0] if tokens.peek_next() is not None: @@ -1069,20 +1081,27 @@ class Config(object): stmt.def_exprs.extend([(val_expr, _make_and(cond_expr, deps)) for val_expr, cond_expr in new_def_exprs]) - # Propagate dependencies to selects + # Propagate dependencies to selects and implies - # Only symbols can select + # Only symbols can select and imply if isinstance(stmt, Symbol): # Propagate 'depends on' dependencies new_selects = [(target, _make_and(cond_expr, depends_on_expr)) for target, cond_expr in new_selects] + new_implies = [(target, _make_and(cond_expr, depends_on_expr)) + for target, cond_expr in new_implies] # Save original stmt.orig_selects.extend(new_selects) + stmt.orig_implies.extend(new_implies) # Finalize with dependencies from enclosing menus and ifs for target, cond in new_selects: - target.rev_dep = _make_or(target.rev_dep, - _make_and(stmt, - _make_and(cond, deps))) + target.rev_dep = \ + _make_or(target.rev_dep, + _make_and(stmt, _make_and(cond, deps))) + for target, cond in new_implies: + target.weak_rev_dep = \ + _make_or(target.weak_rev_dep, + _make_and(stmt, _make_and(cond, deps))) def _parse_expr(self, feed, cur_item, line, filename=None, linenr=None, transform_m=True): @@ -1474,7 +1493,8 @@ class Config(object): # The directly dependent symbols of a symbol are: # - Any symbols whose prompts, default values, rev_dep (select - # condition), or ranges depend on the symbol + # condition), weak_rev_dep (imply condition) or ranges depend on the + # symbol # - Any symbols that belong to the same choice statement as the symbol # (these won't be included in 'dep' as that makes the dependency # graph unwieldy, but Symbol._get_dependent() will include them) @@ -1488,6 +1508,7 @@ class Config(object): add_expr_deps(e, sym) add_expr_deps(sym.rev_dep, sym) + add_expr_deps(sym.weak_rev_dep, sym) for l, u, e in sym.ranges: add_expr_deps(l, sym) @@ -1676,6 +1697,18 @@ class Config(object): self._expr_val_str(cond_expr))) selects_str = "\n".join(selects_str_rows) + # Build implies string + if not sc.orig_implies: + implies_str = " (no implies)" + else: + implies_str_rows = [] + for target, cond_expr in sc.orig_implies: + implies_str_rows.append( + " {0}".format(target.name) if cond_expr is None else + " {0} if {1}".format(target.name, + self._expr_val_str(cond_expr))) + implies_str = "\n".join(implies_str_rows) + res = _lines("Symbol " + ("(no name)" if sc.name is None else sc.name), "Type : " + TYPENAME[sc.type], @@ -1694,9 +1727,16 @@ class Config(object): defaults_str, "Selects:", selects_str, + "Implies:", + implies_str, "Reverse (select-related) dependencies:", - " (no reverse dependencies)" if sc.rev_dep == "n" - else " " + self._expr_val_str(sc.rev_dep), + " (no reverse dependencies)" + if sc.rev_dep == "n" + else " " + self._expr_val_str(sc.rev_dep), + "Weak reverse (imply-related) dependencies:", + " (no weak reverse dependencies)" + if sc.weak_rev_dep == "n" + else " " + self._expr_val_str(sc.weak_rev_dep), "Additional dependencies from enclosing menus " "and ifs:", additional_deps_str, @@ -1907,16 +1947,17 @@ class Symbol(Item): else: # If the symbol is visible and has a user value, use that. - # Otherwise, look at defaults. - use_defaults = True + # Otherwise, look at defaults and weak reverse dependencies + # (implies). + use_defaults_and_weak_rev_deps = True if vis != "n": self.write_to_conf = True if self.user_val is not None: new_val = self.config._eval_min(self.user_val, vis) - use_defaults = False + use_defaults_and_weak_rev_deps = False - if use_defaults: + if use_defaults_and_weak_rev_deps: for val_expr, cond_expr in self.def_exprs: cond_eval = self.config._eval_expr(cond_expr) if cond_eval != "n": @@ -1925,14 +1966,25 @@ class Symbol(Item): cond_eval) break + weak_rev_dep_val = \ + self.config._eval_expr(self.weak_rev_dep) + if weak_rev_dep_val != "n": + self.write_to_conf = True + new_val = self.config._eval_max(new_val, + weak_rev_dep_val) + # Reverse (select-related) dependencies take precedence rev_dep_val = self.config._eval_expr(self.rev_dep) if rev_dep_val != "n": self.write_to_conf = True new_val = self.config._eval_max(new_val, rev_dep_val) - # Promote "m" to "y" for booleans - if new_val == "m" and self.type == BOOL: + # We need to promote "m" to "y" in two circumstances: + # 1) If our type is boolean + # 2) If our weak_rev_dep (from IMPLY) is "y" + if new_val == "m" and \ + (self.type == BOOL or + self.config._eval_expr(self.weak_rev_dep) == "y"): new_val = "y" elif self.type == INT or self.type == HEX: @@ -2167,6 +2219,13 @@ class Symbol(Item): get_referenced_symbols().""" return self.selected_syms + def get_implied_symbols(self): + """Returns the set() of all symbols X for which this symbol has an + 'imply X' or 'imply X if Y' (regardless of whether Y is satisfied or + not). This is a subset of the symbols returned by + get_referenced_symbols().""" + return self.implied_syms + def set_user_value(self, v): """Sets the user value of the symbol. @@ -2282,16 +2341,18 @@ class Symbol(Item): self.ranges = [] # 'range' properties (for int and hex) self.help = None # Help text self.rev_dep = "n" # Reverse (select-related) dependencies + self.weak_rev_dep = "n" # Weak reverse (imply-related) dependencies self.config = None self.parent = None self.user_val = None # Value set by user - # The prompt, default value and select conditions without any + # The prompt, default value, select, and imply conditions without any # dependencies from menus and ifs propagated to them self.orig_prompts = [] self.orig_def_exprs = [] self.orig_selects = [] + self.orig_implies = [] # Dependencies inherited from containing menus and ifs self.deps_from_containing = None @@ -2301,6 +2362,8 @@ class Symbol(Item): # The set of symbols selected by this symbol (see # get_selected_symbols()) self.selected_syms = set() + # The set of symbols implied by this symbol (see get_implied_symbols()) + self.implied_syms = set() # Like 'referenced_syms', but includes symbols from # dependencies inherited from enclosing menus and ifs self.all_referenced_syms = set() @@ -3396,8 +3459,8 @@ def _internal_error(msg): T_OPTIONAL, T_PROMPT, T_DEFAULT, T_BOOL, T_TRISTATE, T_HEX, T_INT, T_STRING, T_DEF_BOOL, T_DEF_TRISTATE, - T_SELECT, T_RANGE, T_OPTION, T_ALLNOCONFIG_Y, T_ENV, - T_DEFCONFIG_LIST, T_MODULES, T_VISIBLE) = range(39) + T_SELECT, T_IMPLY, T_RANGE, T_OPTION, T_ALLNOCONFIG_Y, T_ENV, + T_DEFCONFIG_LIST, T_MODULES, T_VISIBLE) = range(40) # The leading underscore before the function assignments below prevent pydoc # from listing them. The constants could be hidden too, but they're fairly @@ -3414,8 +3477,9 @@ _get_keyword = \ "prompt": T_PROMPT, "default": T_DEFAULT, "bool": T_BOOL, "boolean": T_BOOL, "tristate": T_TRISTATE, "int": T_INT, "hex": T_HEX, "def_bool": T_DEF_BOOL, "def_tristate": T_DEF_TRISTATE, "string": T_STRING, "select": T_SELECT, - "range": T_RANGE, "option": T_OPTION, "allnoconfig_y": T_ALLNOCONFIG_Y, - "env": T_ENV, "defconfig_list": T_DEFCONFIG_LIST, "modules": T_MODULES, + "imply" : T_IMPLY, "range": T_RANGE, "option": T_OPTION, + "allnoconfig_y": T_ALLNOCONFIG_Y, "env": T_ENV, + "defconfig_list": T_DEFCONFIG_LIST, "modules": T_MODULES, "visible": T_VISIBLE}.get # Strings to use for True and False diff --git a/tests/Kbounds b/tests/Kbounds index 9b10a3e..52e61c9 100644 --- a/tests/Kbounds +++ b/tests/Kbounds @@ -39,6 +39,39 @@ config M_SELECTED_TRISTATE config M_SELECTED_M_VISIBLE_TRISTATE tristate "m-selected m-visible tristate" if m +config N_IMPLIER + def_tristate n + imply N_IMPLIED_BOOL + imply N_IMPLIED_TRISTATE + +config M_IMPLIER + def_tristate m + imply M_IMPLIED_BOOL + imply M_IMPLIED_TRISTATE + +config Y_IMPLIER + def_tristate y + imply Y_IMPLIED_BOOL + imply Y_IMPLIED_TRISTATE + +config N_IMPLIED_BOOL + bool "n-implied bool" + +config N_IMPLIED_TRISTATE + tristate "n-implied tristate" + +config M_IMPLIED_BOOL + bool "m-implied bool" + +config M_IMPLIED_TRISTATE + tristate "m-implied tristate" + +config Y_IMPLIED_BOOL + bool "y-implied bool" + +config Y_IMPLIED_TRISTATE + tristate "y-implied tristate" + config STRING string "string" diff --git a/tests/Kchain b/tests/Kchain index 316bb04..dc57ee5 100644 --- a/tests/Kchain +++ b/tests/Kchain @@ -65,50 +65,59 @@ config CHAIN_SELECT_RELAY config CHAIN_16 bool "chain 16" + imply CHAIN_17 -if CHAIN_16 = 0 config CHAIN_17 - tristate "chain 17" + bool "chain 17" + +config CHAIN_IMPLY_RELAY + bool "chain imply relay" + default y + imply CHAIN_18 if CHAIN_17 + +if CHAIN_18 = 0 +config CHAIN_19 + tristate "chain 19" endif menu "chain menu" - depends on CHAIN_17 -config CHAIN_18 - bool "chain 18" + depends on CHAIN_19 +config CHAIN_20 + bool "chain 20" endmenu menu "chain menu visible if" - visible if CHAIN_18 -config CHAIN_19 - bool "chain 19" + visible if CHAIN_20 +config CHAIN_21 + bool "chain 21" endmenu choice CHAIN_CHOICE_1 - tristate "chain choice 1" if CHAIN_19 -config CHAIN_20 - tristate "chain 20" + tristate "chain choice 1" if CHAIN_21 +config CHAIN_22 + tristate "chain 22" config DUMMY_1 tristate "dummy 1" endchoice choice CHAIN_CHOICE_2 tristate "chain choice 2" - depends on CHAIN_20 + depends on CHAIN_22 config DUMMY_2 tristate "dummy 2" -config CHAIN_21 - tristate "chain 18" +config CHAIN_23 + tristate "chain 23" endchoice choice CHAIN_CHOICE_3 tristate "chain choice 3" - default DUMMY_3 if CHAIN_21 -config CHAIN_22 - tristate "chain 22" + default DUMMY_3 if CHAIN_23 +config CHAIN_24 + tristate "chain 24" config DUMMY_3 tristate "dummy 3" endchoice -config CHAIN_23 - string "chain 19" - depends on CHAIN_22 +config CHAIN_25 + string "chain 25" + depends on CHAIN_24 @@ -1,5 +1,11 @@ config D bool "D" + select D29 + imply D30 + +config DUMMY + select D31 if D + imply D32 if D # The symbols below depend on D in different ways @@ -122,6 +128,18 @@ config D27 config D28 bool "D28" if n || ((n != D) || n) +config D29 + tristate "D29" + +config D30 + tristate "D30" + +config D31 + tristate "D31" + +config D32 + tristate "D32" + # # Choices # diff --git a/tests/Klocation_included b/tests/Klocation_included index 1164e58..674116a 100644 --- a/tests/Klocation_included +++ b/tests/Klocation_included @@ -11,6 +11,8 @@ config S bool select A if NOT_DEFINED = y select E if A + imply A + imply E if A endmenu choice bool "C" @@ -18,6 +18,8 @@ config MANY_REF depends on H select I if J = K || L != M select N if (A || !(B && (C = O))) + imply P if Q = R || S != T + imply U if (A || !(B && (C = V))) endif diff --git a/tests/Ktext b/tests/Ktext index dd9fd82..c645bde 100644 --- a/tests/Ktext +++ b/tests/Ktext @@ -7,6 +7,8 @@ config ADVANCED tristate "advanced prompt 1" if y || (BASIC && BASIC) select SELECTED_1 if BASIC && DUMMY select SELECTED_2 if !(DUMMY || BASIC) + imply IMPLIED_1 if BASIC || DUMMY + imply IMPLIED_2 if !(DUMMY && BASIC) default y if BASIC && !BASIC default n if BASIC = DUMMY @@ -21,6 +23,10 @@ config SELECTING_1 select ADVANCED if BASIC config SELECTING_2 select ADVANCED if !BASIC +config IMPLYING_1 + imply ADVANCED if DUMMY +config IMPLYING_2 + imply ADVANCED if !DUMMY config INT int diff --git a/testsuite.py b/testsuite.py index e08743c..f713da0 100644 --- a/testsuite.py +++ b/testsuite.py @@ -304,6 +304,12 @@ def run_selftests(): verify_bounds("Y_SELECTED_TRISTATE", None, None) verify_bounds("M_SELECTED_TRISTATE", "m", "y") verify_bounds("M_SELECTED_M_VISIBLE_TRISTATE", None, None) + verify_bounds("N_IMPLIED_BOOL", "n", "y") + verify_bounds("N_IMPLIED_TRISTATE", "n", "y") + verify_bounds("M_IMPLIED_BOOL", "n", "y") + verify_bounds("M_IMPLIED_TRISTATE", "n", "y") + verify_bounds("Y_IMPLIED_BOOL", "n", "y") + verify_bounds("Y_IMPLIED_TRISTATE", "n", "y") verify_bounds("STRING", None, None) verify_bounds("INT", None, None) verify_bounds("HEX", None, None) @@ -490,8 +496,12 @@ def run_selftests(): (no default values) Selects: (no selects) + Implies: + (no implies) Reverse (select-related) dependencies: (no reverse dependencies) + Weak reverse (imply-related) dependencies: + (no weak reverse dependencies) Additional dependencies from enclosing menus and ifs: (no additional dependencies) Locations: Kconfiglib/tests/Ktext:1""") @@ -519,11 +529,16 @@ def run_selftests(): Selects: SELECTED_1 if BASIC && DUMMY (value: "n") SELECTED_2 if !(DUMMY || BASIC) (value: "y") + Implies: + IMPLIED_1 if BASIC || DUMMY (value: "n") + IMPLIED_2 if !(DUMMY && BASIC) (value: "y") Reverse (select-related) dependencies: SELECTING_1 && BASIC || SELECTING_2 && !BASIC (value: "n") + Weak reverse (imply-related) dependencies: + IMPLYING_1 && DUMMY || IMPLYING_2 && !DUMMY (value: "n") Additional dependencies from enclosing menus and ifs: !BASIC && !BASIC (value: "y") - Locations: Kconfiglib/tests/Ktext:6 Kconfiglib/tests/Ktext:13""") + Locations: Kconfiglib/tests/Ktext:6 Kconfiglib/tests/Ktext:15""") verify_print(c["HAS_RANGES"], """ Symbol HAS_RANGES @@ -545,11 +560,15 @@ def run_selftests(): (no default values) Selects: (no selects) + Implies: + (no implies) Reverse (select-related) dependencies: (no reverse dependencies) + Weak reverse (imply-related) dependencies: + (no weak reverse dependencies) Additional dependencies from enclosing menus and ifs: (no additional dependencies) - Locations: Kconfiglib/tests/Ktext:29""") + Locations: Kconfiglib/tests/Ktext:35""") # Printing of Choice @@ -570,7 +589,7 @@ def run_selftests(): CHOICE_ITEM_1 CHOICE_ITEM_2 CHOICE_ITEM_3 Additional dependencies from enclosing menus and ifs: (no additional dependencies) - Locations: Kconfiglib/tests/Ktext:35""") + Locations: Kconfiglib/tests/Ktext:41""") c["CHOICE_ITEM_2"].set_user_value("y") @@ -591,7 +610,7 @@ def run_selftests(): CHOICE_ITEM_1 CHOICE_ITEM_2 CHOICE_ITEM_3 Additional dependencies from enclosing menus and ifs: (no additional dependencies) - Locations: Kconfiglib/tests/Ktext:35""") + Locations: Kconfiglib/tests/Ktext:41""") # Printing of Menu @@ -602,7 +621,7 @@ def run_selftests(): 'visible if' dependencies : (no dependencies) Additional dependencies from enclosing menus and ifs: (no additional dependencies) - Location: Kconfiglib/tests/Ktext:47""") + Location: Kconfiglib/tests/Ktext:53""") verify_print(c.get_menus()[1], """ Menu @@ -611,7 +630,7 @@ def run_selftests(): 'visible if' dependencies : !DUMMY (value: "y") Additional dependencies from enclosing menus and ifs: !DUMMY (value: "y") - Location: Kconfiglib/tests/Ktext:51""") + Location: Kconfiglib/tests/Ktext:57""") # Printing of Comment @@ -621,7 +640,7 @@ def run_selftests(): Dependencies: (no dependencies) Additional dependencies from enclosing menus and ifs: (no additional dependencies) - Location: Kconfiglib/tests/Ktext:57""") + Location: Kconfiglib/tests/Ktext:63""") verify_print(c.get_comments()[1], """ Comment @@ -629,7 +648,7 @@ def run_selftests(): Dependencies: !BASIC (value: "y") Additional dependencies from enclosing menus and ifs: !DUMMY (value: "y") - Location: Kconfiglib/tests/Ktext:60""") + Location: Kconfiglib/tests/Ktext:66""") verify_equals(c["NO_HELP"].get_help(), None) verify_equals(c["EMPTY_HELP"].get_help(), "") @@ -717,9 +736,9 @@ def run_selftests(): verify_def_locations("M", ("Kconfiglib/tests/Klocation_included", 6)) verify_def_locations("N", - ("Kconfiglib/tests/Klocation_included", 17)) - verify_def_locations("O", ("Kconfiglib/tests/Klocation_included", 19)) + verify_def_locations("O", + ("Kconfiglib/tests/Klocation_included", 21)) verify_def_locations("NOT_DEFINED") # No locations def verify_ref_locations(sym_name, *locs): @@ -746,8 +765,10 @@ def run_selftests(): ("Kconfiglib/tests/Klocation_included", 9), ("Kconfiglib/tests/Klocation_included", 12), ("Kconfiglib/tests/Klocation_included", 13), - ("Kconfiglib/tests/Klocation_included", 33), - ("Kconfiglib/tests/Klocation_included", 38), + ("Kconfiglib/tests/Klocation_included", 14), + ("Kconfiglib/tests/Klocation_included", 15), + ("Kconfiglib/tests/Klocation_included", 35), + ("Kconfiglib/tests/Klocation_included", 40), ("Kconfiglib/tests/Klocation", 65), ("Kconfiglib/tests/Klocation", 66), ("Kconfiglib/tests/Klocation", 67)) @@ -756,8 +777,8 @@ def run_selftests(): ("Kconfiglib/tests/Klocation", 12), ("Kconfiglib/tests/Klocation", 29), ("Kconfiglib/tests/Klocation_included", 12), - ("Kconfiglib/tests/Klocation_included", 33), - ("Kconfiglib/tests/Klocation_included", 39)) + ("Kconfiglib/tests/Klocation_included", 35), + ("Kconfiglib/tests/Klocation_included", 41)) # Location queries for choices @@ -780,9 +801,9 @@ def run_selftests(): verify_choice_locations(choice_1, ("Kconfiglib/tests/Klocation", 15), - ("Kconfiglib/tests/Klocation_included", 22)) + ("Kconfiglib/tests/Klocation_included", 24)) verify_choice_locations(choice_2, - ("Kconfiglib/tests/Klocation_included", 15)) + ("Kconfiglib/tests/Klocation_included", 17)) # Location queries for menus and comments @@ -803,7 +824,7 @@ def run_selftests(): verify_location(menu_1, ("Kconfiglib/tests/Klocation", 9)) verify_location(menu_2, ("Kconfiglib/tests/Klocation_included", 5)) verify_location(comment_1, ("Kconfiglib/tests/Klocation", 31)) - verify_location(comment_2, ("Kconfiglib/tests/Klocation_included", 34)) + verify_location(comment_2, ("Kconfiglib/tests/Klocation_included", 36)) # # Visibility queries @@ -1218,7 +1239,7 @@ def run_selftests(): verify_sym_refs("NO_REF", [], []) verify_sym_refs("ONE_REF", ["A"], ["A"]) own_refs = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", - "M", "N", "O"] + "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V"] verify_sym_refs("MANY_REF", own_refs, own_refs + ["IF_REF_1", "IF_REF_2", "MENU_REF_1", @@ -1268,6 +1289,28 @@ def run_selftests(): verify_selects("MANY_REF", ["I", "N"]) # + # get_implied_symbols() (same test file) + # + + def verify_implies(sym_name, imply_names): + sym = c[sym_name] + sym_implies = sym.get_implied_symbols() + verify(len(sym_implies) == len(imply_names), + "Wrong number of implies for {0}".format(sym_name)) + for imply_name in imply_names: + implied_sym = c[imply_name] + verify(implied_sym in sym_implies, + "{0} should be implied by {1}".format(imply_name, sym_name)) + + verify_implies("n", []) + verify_implies("m", []) + verify_implies("y", []) + verify_implies("UNAME_RELEASE", []) + + verify_implies("NO_REF", []) + verify_implies("MANY_REF", ["P", "U"]) + + # # get_defconfig_filename() # @@ -1785,7 +1828,7 @@ def run_selftests(): # Test twice to cover dependency caching for i in range(0, 2): - n_deps = 28 + n_deps = 32 # Verify that D1, D2, .., D<n_deps> are dependent on D verify_dependent("D", ["D{0}".format(i) for i in range(1, n_deps + 1)]) # Choices @@ -1800,7 +1843,7 @@ def run_selftests(): c = kconfiglib.Config("Kconfiglib/tests/Kchain") for i in range(0, 2): - verify(c["CHAIN_23"] in c["CHAIN_1"]._get_dependent(), + verify(c["CHAIN_25"] in c["CHAIN_1"]._get_dependent(), "Dependency chain broken") print("\nAll selftests passed\n" if _all_ok else @@ -2003,6 +2046,7 @@ def test_call_all(conf): s.get_assignable_values() s.get_config() s.get_help() + s.get_implied_symbols() s.get_lower_bound() s.get_name() s.get_parent() |
