diff options
Diffstat (limited to 'kconfiglib.py')
| -rw-r--r-- | kconfiglib.py | 203 |
1 files changed, 118 insertions, 85 deletions
diff --git a/kconfiglib.py b/kconfiglib.py index 25bb380..3262b43 100644 --- a/kconfiglib.py +++ b/kconfiglib.py @@ -360,13 +360,13 @@ class Config(object): # Predefined symbol. DEFCONFIG_LIST uses this. uname_sym = self._lookup_const_sym("UNAME_RELEASE") uname_sym._type = STRING - uname_sym.defaults.append( - (self._lookup_const_sym(platform.uname()[2]), - self.y)) # env_var doubles as the SYMBOL_AUTO flag from the C implementation, so # just set it to something. The naming breaks a bit here, but it's # pretty obscure. uname_sym.env_var = "<uname release>" + uname_sym.defaults.append( + (self._lookup_const_sym(platform.uname()[2]), + self.y)) self.syms["UNAME_RELEASE"] = uname_sym self.top_node = MenuNode() @@ -418,8 +418,8 @@ class Config(object): if self.defconfig_list is None: return None - for filename, cond_expr in self.defconfig_list.defaults: - if eval_expr(cond_expr): + for filename, cond in self.defconfig_list.defaults: + if expr_value(cond): filename = self._expand_sym_refs(filename.str_value) try: with self._open(filename) as f: @@ -559,7 +559,7 @@ class Config(object): self._line = s del self._tokens[0] - return eval_expr(self._parse_expr(True)) + return expr_value(self._parse_expr(True)) def unset_values(self): """ @@ -921,7 +921,6 @@ class Config(object): self._reuse_line = False while self._line.endswith("\\\n"): - # TODO: Can hang if the file ends with a backslash self._line = self._line[:-2] + self._file.readline() self._linenr += 1 @@ -1346,39 +1345,39 @@ class Config(object): node.prompt = None # Add the new defaults, with dependencies propagated - for val_expr, cond_expr in defaults: + for val_expr, cond in defaults: node.item.defaults.append( - (val_expr, self._make_and(cond_expr, node.dep))) + (val_expr, self._make_and(cond, node.dep))) # Add the new ranges, with dependencies propagated - for low, high, cond_expr in ranges: + for low, high, cond in ranges: node.item.ranges.append( - (low, high, self._make_and(cond_expr, node.dep))) + (low, high, self._make_and(cond, node.dep))) # Handle selects - for target, cond_expr in selects: + for target, cond in selects: # Only stored for convenience. Not used during evaluation. node.item.selects.append( - (target, self._make_and(cond_expr, node.dep))) + (target, self._make_and(cond, node.dep))) # Modify the dependencies of the selected symbol target.rev_dep = \ self._make_or(target.rev_dep, self._make_and(node.item, - self._make_and(cond_expr, + self._make_and(cond, node.dep))) # Handle implies - for target, cond_expr in implies: + for target, cond in implies: # Only stored for convenience. Not used during evaluation. node.item.implies.append( - (target, self._make_and(cond_expr, node.dep))) + (target, self._make_and(cond, node.dep))) # Modify the dependencies of the implied symbol target.weak_rev_dep = \ self._make_or(target.weak_rev_dep, self._make_and(node.item, - self._make_and(cond_expr, + self._make_and(cond, node.dep))) def _parse_expr(self, transform_m): @@ -1559,8 +1558,8 @@ class Config(object): add_fn(config_string) sym._already_written = True - elif eval_expr(node.dep) and \ - ((node.item == MENU and eval_expr(node.visibility)) or + elif expr_value(node.dep) and \ + ((node.item == MENU and expr_value(node.visibility)) or node.item == COMMENT): add_fn("\n#\n# {}\n#\n".format(node.prompt[0])) @@ -1994,8 +1993,8 @@ class Symbol(object): base = _TYPE_TO_BASE[self._type] # Check if a range is in effect - for low_expr, high_expr, cond_expr in self.ranges: - if eval_expr(cond_expr): + for low_expr, high_expr, cond in self.ranges: + if expr_value(cond): has_active_range = True low = int(low_expr.str_value, base) if \ @@ -2020,8 +2019,8 @@ class Symbol(object): else: # No user value or invalid user value. Look at defaults. - for val_expr, cond_expr in self.defaults: - if eval_expr(cond_expr): + for val_expr, cond in self.defaults: + if expr_value(cond): self._write_to_conf = True # Similarly to above, well-formed defaults are @@ -2059,8 +2058,8 @@ class Symbol(object): if vis and self.user_str_value is not None: val = self.user_str_value else: - for val_expr, cond_expr in self.defaults: - if eval_expr(cond_expr): + for val_expr, cond in self.defaults: + if expr_value(cond): self._write_to_conf = True val = val_expr.str_value break @@ -2096,22 +2095,22 @@ class Symbol(object): # (implies) for default, cond in self.defaults: - cond_val = eval_expr(cond) + cond_val = expr_value(cond) if cond_val: - val = min(cond_val, eval_expr(default)) + val = min(cond_val, expr_value(default)) self._write_to_conf = True break # Weak reverse dependencies are only considered if our # direct dependencies are met - if eval_expr(self.direct_dep): - weak_rev_dep_val = eval_expr(self.weak_rev_dep) + if expr_value(self.direct_dep): + weak_rev_dep_val = expr_value(self.weak_rev_dep) if weak_rev_dep_val: val = max(weak_rev_dep_val, val) self._write_to_conf = True # Reverse (select-related) dependencies take precedence - rev_dep_val = eval_expr(self.rev_dep) + rev_dep_val = expr_value(self.rev_dep) if rev_dep_val: val = max(rev_dep_val, val) self._write_to_conf = True @@ -2139,7 +2138,7 @@ class Symbol(object): # 1) If our type is boolean # 2) If our weak_rev_dep (from IMPLY) is y if val == 1 and \ - (self.type == BOOL or eval_expr(self.weak_rev_dep) == 2): + (self.type == BOOL or expr_value(self.weak_rev_dep) == 2): val = 2 self._cached_tri_val = val @@ -2259,38 +2258,51 @@ class Symbol(object): Prints some information about the symbol (including its name, value, visibility, and location(s)) when it is evaluated. """ - fields = [ - "symbol " + self.name, - _TYPENAME[self.type], - 'value "{}"'.format(self.str_value), - "visibility " + TRI_TO_STR[self.visibility], - ] + fields = [] - if self.user_str_value is not None: - fields.append('user value "{}"'.format(self.user_str_value)) + fields.append("symbol " + self.name) + fields.append(_TYPENAME[self.type]) - if self.choice is not None: - fields.append("choice symbol") + for node in self.nodes: + if node.prompt is not None: + fields.append('"{}"'.format(node.prompt[0])) - if self.is_allnoconfig_y: - fields.append("allnoconfig_y") + fields.append('value "{}"'.format(self.str_value)) - if self is self.config.defconfig_list: - fields.append("is the defconfig_list symbol") + if not self.is_constant: + # These aren't helpful to show for constant symbols - if self.env_var is not None: - fields.append("from environment variable " + self.env_var) + if self.user_str_value is not None: + fields.append('user value "{}"'.format(self.user_str_value)) - if self is self.config.modules: - fields.append("is the modules symbol") + fields.append("visibility " + TRI_TO_STR[self.visibility]) - fields.append("direct deps " + TRI_TO_STR[eval_expr(self.direct_dep)]) + if self.choice is not None: + fields.append("choice symbol") + + if self.is_allnoconfig_y: + fields.append("allnoconfig_y") + + if self is self.config.defconfig_list: + fields.append("is the defconfig_list symbol") + + if self.env_var is not None: + fields.append("from environment variable " + self.env_var) + + if self is self.config.modules: + fields.append("is the modules symbol") + + fields.append("direct deps " + + TRI_TO_STR[expr_value(self.direct_dep)]) if self.nodes: for node in self.nodes: fields.append("{}:{}".format(node.filename, node.linenr)) else: - fields.append("undefined") + if self.is_constant: + fields.append("constant") + else: + fields.append("undefined") return "<{}>".format(", ".join(fields)) @@ -2358,11 +2370,11 @@ class Symbol(object): if not vis: return "" - rev_dep_val = eval_expr(self.rev_dep) + rev_dep_val = expr_value(self.rev_dep) if vis == 2: if not rev_dep_val: - if self.type == BOOL or eval_expr(self.weak_rev_dep) == 2: + if self.type == BOOL or expr_value(self.weak_rev_dep) == 2: return "ny" return "nmy" @@ -2371,14 +2383,14 @@ class Symbol(object): # rev_dep_val == 1 - if self.type == BOOL or eval_expr(self.weak_rev_dep) == 2: + if self.type == BOOL or expr_value(self.weak_rev_dep) == 2: return "y" return "my" # vis == 1 if not rev_dep_val: - return "m" if eval_expr(self.weak_rev_dep) != 2 else "y" + return "m" if expr_value(self.weak_rev_dep) != 2 else "y" if rev_dep_val == 2: return "y" @@ -2451,10 +2463,14 @@ class Symbol(object): Invalidates the symbol and all symbols and choices that (possibly indirectly) depend on it """ - self._invalidate() + # Constant symbols must never be invalidated, because they lose their + # value. They never appear as dependencies, but can still be manually + # assigned a user value (and that's OK, though pointless). + if not self.is_constant: + self._invalidate() - for item in self._get_dependent(): - item._invalidate() + for item in self._get_dependent(): + item._invalidate() def _get_dependent(self): """ @@ -2708,8 +2724,8 @@ class Choice(object): """ See the class documentation. """ - for sym, cond_expr in self.defaults: - if eval_expr(cond_expr) and sym.visibility: + for sym, cond in self.defaults: + if expr_value(cond) and sym.visibility: return sym # Otherwise, pick the first visible symbol, if any @@ -2761,19 +2777,38 @@ class Choice(object): """ TODO """ - fields = [ - "choice" if self.name is None else "choice " + self.name, - _TYPENAME[self.type], - "mode " + self.str_value, - "visibility " + TRI_TO_STR[self.visibility], - ] + fields = [] - if self.is_optional: - fields.append("optional") + fields.append("choice" if self.name is None else \ + "choice " + self.name) + fields.append(_TYPENAME[self.type]) + + for node in self.nodes: + if node.prompt is not None: + fields.append('"{}"'.format(node.prompt[0])) + + fields.append("mode " + self.str_value) + + if self.user_str_value is not None: + fields.append('user mode {}'.format(self.user_str_value)) if self.selection is not None: fields.append("{} selected".format(self.selection.name)) + if self.user_selection is not None: + user_sel_str = "{} selected by user" \ + .format(self.user_selection.name) + + if self.selection is not self.user_selection: + user_sel_str += " (overriden)" + + fields.append(user_sel_str) + + fields.append("visibility " + TRI_TO_STR[self.visibility]) + + if self.is_optional: + fields.append("optional") + for node in self.nodes: fields.append("{}:{}".format(node.filename, node.linenr)) @@ -2932,46 +2967,42 @@ class MenuNode(object): ) def __repr__(self): + """ + TODO + """ fields = [] if isinstance(self.item, Symbol): fields.append("menu node for symbol " + self.item.name) - elif isinstance(self.item, Choice): s = "menu node for choice" if self.item.name is not None: s += " " + self.item.name fields.append(s) - elif self.item == MENU: fields.append("menu node for menu") - elif self.item == COMMENT: fields.append("menu node for comment") - elif self.item is None: fields.append("menu node for if (should not appear in the final " " tree)") - else: raise InternalError("unable to determine type in " "MenuNode.__repr__()") - fields.append("{}:{}".format(self.filename, self.linenr)) - if self.prompt is not None: fields.append('prompt "{}" (visibility {})' .format(self.prompt[0], - TRI_TO_STR[eval_expr(self.prompt[1])])) + TRI_TO_STR[expr_value(self.prompt[1])])) if isinstance(self.item, Symbol) and self.is_menuconfig: fields.append("is menuconfig") - fields.append("deps " + TRI_TO_STR[eval_expr(self.dep)]) + fields.append("deps " + TRI_TO_STR[expr_value(self.dep)]) if self.item == MENU: fields.append("'visible if' deps " + \ - TRI_TO_STR[eval_expr(self.visibility)]) + TRI_TO_STR[expr_value(self.visibility)]) if isinstance(self.item, (Symbol, Choice)) and self.help is not None: fields.append("has help") @@ -2982,6 +3013,8 @@ class MenuNode(object): if self.next is not None: fields.append("has next") + fields.append("{}:{}".format(self.filename, self.linenr)) + return "<{}>".format(", ".join(fields)) class KconfigSyntaxError(Exception): @@ -3000,7 +3033,7 @@ class InternalError(Exception): # Public functions # -def eval_expr(expr): +def expr_value(expr): """ TODO """ @@ -3008,18 +3041,18 @@ def eval_expr(expr): return expr.tri_value if expr[0] == AND: - v1 = eval_expr(expr[1]) + v1 = expr_value(expr[1]) # Short-circuit the n case as an optimization (~5% faster # allnoconfig.py and allyesconfig.py, as of writing) - return 0 if not v1 else min(v1, eval_expr(expr[2])) + return 0 if not v1 else min(v1, expr_value(expr[2])) if expr[0] == OR: - v1 = eval_expr(expr[1]) + v1 = expr_value(expr[1]) # Short-circuit the y case as an optimization - return 2 if v1 == 2 else max(v1, eval_expr(expr[2])) + return 2 if v1 == 2 else max(v1, expr_value(expr[2])) if expr[0] == NOT: - return 2 - eval_expr(expr[1]) + return 2 - expr_value(expr[1]) if expr[0] in _RELATIONS: # Implements <, <=, >, >= comparisons as well. These were added to @@ -3096,7 +3129,7 @@ def _get_visibility(sc): for node in sc.nodes: if node.prompt: - vis = max(vis, eval_expr(node.prompt[1])) + vis = max(vis, expr_value(node.prompt[1])) if isinstance(sc, Symbol) and sc.choice is not None: if sc.choice._type == TRISTATE and sc._type != TRISTATE and \ |
