summaryrefslogtreecommitdiff
path: root/kconfiglib.py
diff options
context:
space:
mode:
Diffstat (limited to 'kconfiglib.py')
-rw-r--r--kconfiglib.py660
1 files changed, 342 insertions, 318 deletions
diff --git a/kconfiglib.py b/kconfiglib.py
index 083ef8e..6365d60 100644
--- a/kconfiglib.py
+++ b/kconfiglib.py
@@ -245,9 +245,12 @@ This organization mirrors the C implementation. MenuNode is called
'struct menu' there, but I thought "menu" was a confusing name.
It is possible to give a Choice a name and define it in multiple locations,
-hence why Choice.nodes is also a list. In practice, you're unlikely to ever see
-a choice defined in more than one location. I don't think I've even seen a
-named choice outside of the test suite.
+hence why Choice.nodes is also a list.
+
+As a convenience, the properties added at a particular definition location are
+available on the MenuNode itself, in e.g. MenuNode.defaults. This is helpful
+when generating documentation, so that symbols/choices defined in multiple
+locations can be shown with the correct properties at each location.
Intro to expressions
@@ -419,11 +422,10 @@ class Kconfig(object):
the 'Intro to the menu tree' section in the module docstring.
const_syms:
- A dictionary like 'syms' for constant (quoted) symbols.
+ A dictionary like 'syms' for constant (quoted) symbols
named_choices:
- A dictionary like 'syms' for named choices (choice FOO). This is for
- completeness. I've never seen a named choice outside of the test suite.
+ A dictionary like 'syms' for named choices (choice FOO)
defined_syms:
A list with all defined symbols, in the same order as they appear in the
@@ -710,10 +712,7 @@ class Kconfig(object):
self._file = self._open(filename)
try:
- self._parse_block(None, # end_token
- self.top_node, # parent
- self.top_node, # prev
- self.y) # visible_if_deps
+ self._parse_block(None, self.top_node, self.top_node)
except UnicodeDecodeError as e:
_decoding_error(e, self._filename)
@@ -723,7 +722,7 @@ class Kconfig(object):
self._parsing_kconfigs = False
# Do various post-processing of the menu tree
- _finalize_tree(self.top_node)
+ self._finalize_tree(self.top_node, self.y)
# Do sanity checks. Some of these depend on everything being
@@ -1885,7 +1884,7 @@ class Kconfig(object):
return (OR, e1, e2)
- def _parse_block(self, end_token, parent, prev, visible_if_deps):
+ def _parse_block(self, end_token, parent, prev):
# Parses a block, which is the contents of either a file or an if,
# menu, or choice statement.
#
@@ -1905,10 +1904,6 @@ class Kconfig(object):
# Choice): After parsing the children, the 'next' pointer is assigned
# to the 'list' pointer to "tilt up" the children above the node.
#
- # visible_if_deps:
- # 'visible if' dependencies from enclosing menus. Propagated to
- # Symbol and Choice prompts.
- #
# Returns the final menu node in the block (or 'prev' if the block is
# empty). This allows chaining.
@@ -1938,7 +1933,7 @@ class Kconfig(object):
sym.nodes.append(node)
- self._parse_properties(node, visible_if_deps)
+ self._parse_properties(node)
if node.is_menuconfig and not node.prompt:
self._warn("the menuconfig symbol {} has no prompt"
@@ -1949,7 +1944,7 @@ class Kconfig(object):
elif t0 == _T_SOURCE:
self._enter_file(os.path.expandvars(self._expect_str_and_eol()))
- prev = self._parse_block(None, parent, prev, visible_if_deps)
+ prev = self._parse_block(None, parent, prev)
self._leave_file()
elif t0 == _T_RSOURCE:
@@ -1957,7 +1952,7 @@ class Kconfig(object):
os.path.dirname(self._filename),
os.path.expandvars(self._expect_str_and_eol())
))
- prev = self._parse_block(None, parent, prev, visible_if_deps)
+ prev = self._parse_block(None, parent, prev)
self._leave_file()
elif t0 in (_T_GSOURCE, _T_GRSOURCE):
@@ -1986,7 +1981,7 @@ class Kconfig(object):
filename = os.path.relpath(filename, self.srctree)
self._enter_file(filename)
- prev = self._parse_block(None, parent, prev, visible_if_deps)
+ prev = self._parse_block(None, parent, prev)
self._leave_file()
elif t0 == end_token:
@@ -2002,13 +1997,9 @@ class Kconfig(object):
node.filename = self._filename
node.linenr = self._linenr
- node.dep = self._make_and(
- self._parse_expr(True),
- # See similar code in _parse_properties()
- parent.item if isinstance(parent.item, Choice)
- else parent.dep)
+ node.dep = self._parse_expr(True)
- self._parse_block(_T_ENDIF, node, node, visible_if_deps)
+ self._parse_block(_T_ENDIF, node, node)
node.list = node.next
prev.next = prev = node
@@ -2018,18 +2009,14 @@ class Kconfig(object):
node.kconfig = self
node.item = MENU
node.is_menuconfig = True
+ node.prompt = (self._expect_str_and_eol(), self.y)
node.visibility = self.y
node.parent = parent
node.filename = self._filename
node.linenr = self._linenr
- prompt = self._expect_str_and_eol()
- self._parse_properties(node, visible_if_deps)
- node.prompt = (prompt, node.dep)
-
- self._parse_block(_T_ENDMENU, node, node,
- self._make_and(visible_if_deps,
- node.visibility))
+ self._parse_properties(node)
+ self._parse_block(_T_ENDMENU, node, node)
node.list = node.next
prev.next = prev = node
@@ -2039,14 +2026,13 @@ class Kconfig(object):
node.kconfig = self
node.item = COMMENT
node.is_menuconfig = False
+ node.prompt = (self._expect_str_and_eol(), self.y)
node.list = None
node.parent = parent
node.filename = self._filename
node.linenr = self._linenr
- prompt = self._expect_str_and_eol()
- self._parse_properties(node, visible_if_deps)
- node.prompt = (prompt, node.dep)
+ self._parse_properties(node)
prev.next = prev = node
@@ -2079,8 +2065,8 @@ class Kconfig(object):
node.filename = self._filename
node.linenr = self._linenr
- self._parse_properties(node, visible_if_deps)
- self._parse_block(_T_ENDCHOICE, node, node, visible_if_deps)
+ self._parse_properties(node)
+ self._parse_block(_T_ENDCHOICE, node, node)
node.list = node.next
choice.nodes.append(node)
@@ -2113,33 +2099,33 @@ class Kconfig(object):
self._parse_error("extra tokens at end of line")
return expr
- def _parse_properties(self, node, visible_if_deps):
- # Parses properties for symbols, menus, choices, and comments. Also
- # takes care of propagating dependencies from the menu node to the
- # properties of the item (this mirrors the C tools, though they do it
- # after parsing).
+ def _parse_properties(self, node):
+ # Parses and adds properties to the MenuNode 'node' (type, 'prompt',
+ # 'default's, etc.) Properties are later copied up to symbols and
+ # choices in a separate pass after parsing, in _propagate_deps().
#
- # node:
- # The menu node we're parsing properties on. Prompt, help text,
- # 'depends on', and 'visible if' properties apply to the Menu node,
- # while other properties apply to the contained item.
+ # An older version of this code added properties directly to symbols
+ # and choices instead of to their menu nodes (and handled dependency
+ # propagation simultaneously), but that loses information on where a
+ # property is added when a symbol or choice is defined in multiple
+ # locations. Some Kconfig configuration systems rely heavily on such
+ # symbols, and better docs can be generated by keeping track of where
+ # properties are added.
#
- # visible_if_deps:
- # 'visible if' dependencies from enclosing menus. Propagated to
- # Symbol and Choice prompts.
-
- # New properties encountered at this location. A local 'depends on'
- # only applies to these, in case a symbol is defined in multiple
- # locations.
- defaults = []
- selects = []
- implies = []
- ranges = []
-
- # Menu node dependencies from 'depends on'. Will get propagated to the
- # properties above.
+ # node:
+ # The menu node we're parsing properties on
+
+ # Dependencies from 'depends on'. Will get propagated to the properties
+ # below.
node.dep = self.y
+ # Properties added at this location. A local 'depends on' only applies
+ # to these, in case a symbol is defined in multiple locations.
+ node.defaults = []
+ node.selects = []
+ node.implies = []
+ node.ranges = []
+
while self._next_line():
t0 = self._next_token()
if t0 is None:
@@ -2148,8 +2134,7 @@ class Kconfig(object):
if t0 in _TYPE_TOKENS:
new_type = _TOKEN_TO_TYPE[t0]
- if node.item.orig_type != UNKNOWN and \
- node.item.orig_type != new_type:
+ if node.item.orig_type not in (UNKNOWN, new_type):
self._warn("{} defined with multiple types, {} will be used"
.format(_name_and_loc(node.item),
TYPE_TO_STR[new_type]))
@@ -2228,31 +2213,32 @@ class Kconfig(object):
if not isinstance(node.item, Symbol):
self._parse_error("only symbols can select")
- selects.append((self._expect_nonconst_sym(),
- self._parse_cond()))
+ node.selects.append((self._expect_nonconst_sym(),
+ self._parse_cond()))
elif t0 == _T_IMPLY:
if not isinstance(node.item, Symbol):
self._parse_error("only symbols can imply")
- implies.append((self._expect_nonconst_sym(),
- self._parse_cond()))
+ node.implies.append((self._expect_nonconst_sym(),
+ self._parse_cond()))
elif t0 == _T_DEFAULT:
- defaults.append((self._parse_expr(False), self._parse_cond()))
+ node.defaults.append((self._parse_expr(False),
+ self._parse_cond()))
elif t0 in (_T_DEF_BOOL, _T_DEF_TRISTATE):
new_type = _TOKEN_TO_TYPE[t0]
- if node.item.orig_type != UNKNOWN and \
- node.item.orig_type != new_type:
+ if node.item.orig_type not in (UNKNOWN, new_type):
self._warn("{} defined with multiple types, {} will be used"
.format(_name_and_loc(node.item),
TYPE_TO_STR[new_type]))
node.item.orig_type = new_type
- defaults.append((self._parse_expr(False), self._parse_cond()))
+ node.defaults.append((self._parse_expr(False),
+ self._parse_cond()))
elif t0 == _T_PROMPT:
# 'prompt' properties override each other within a single
@@ -2265,9 +2251,9 @@ class Kconfig(object):
node.prompt = (self._expect_str(), self._parse_cond())
elif t0 == _T_RANGE:
- ranges.append((self._expect_sym(),
- self._expect_sym(),
- self._parse_cond()))
+ node.ranges.append((self._expect_sym(),
+ self._expect_sym(),
+ self._parse_cond()))
elif t0 == _T_OPTION:
if self._check_token(_T_ENV):
@@ -2283,7 +2269,7 @@ class Kconfig(object):
"set".format(node.item.name, env_var),
self._filename, self._linenr)
else:
- defaults.append(
+ node.defaults.append(
(self._lookup_const_sym(os.environ[env_var]),
self.y))
@@ -2341,72 +2327,7 @@ class Kconfig(object):
# Reuse the tokens for the non-property line later
self._has_tokens = True
self._tokens_i = -1
- break
-
- # Done parsing properties. Now add the new
- # prompts/defaults/selects/implies/ranges properties, with dependencies
- # from node.dep propagated.
-
- # First propagate parent dependencies to node.dep
-
- # If the parent node holds a Choice, we use the Choice itself as the
- # parent dependency. This matches the C implementation, and makes sense
- # as the value (mode) of the choice limits the visibility of the
- # contained choice symbols. Due to the similar interface, Choice works
- # as a drop-in replacement for Symbol here.
- node.dep = self._make_and(
- node.dep,
- node.parent.item if isinstance(node.parent.item, Choice)
- else node.parent.dep)
-
- if isinstance(node.item, (Symbol, Choice)):
- # See the Symbol/Choice class documentation
- node.item.direct_dep = \
- self._make_or(node.item.direct_dep, node.dep)
-
- # Set the prompt, with dependencies propagated
- if node.prompt:
- node.prompt = \
- (node.prompt[0],
- self._make_and(node.prompt[1],
- self._make_and(node.dep, visible_if_deps)))
-
- # Add the new defaults, with dependencies propagated
- for val_expr, cond in defaults:
- node.item.defaults.append(
- (val_expr, self._make_and(cond, node.dep)))
-
- # Add the new ranges, with dependencies propagated
- for low, high, cond in ranges:
- node.item.ranges.append(
- (low, high, self._make_and(cond, node.dep)))
-
- # Handle selects
- for target, cond in selects:
- # Only stored for inspection. Not used during evaluation.
- node.item.selects.append(
- (target, self._make_and(cond, node.dep)))
-
- # Modify the dependencies of the selected symbol
- # Warning: See _warn_select_unsatisfied_deps()
- target.rev_dep = \
- self._make_or(target.rev_dep,
- self._make_and(node.item,
- self._make_and(cond,
- node.dep)))
-
- # Handle implies
- for target, cond in implies:
- # Only stored for inspection. Not used during evaluation.
- node.item.implies.append(
- (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,
- node.dep)))
+ return
def _parse_expr(self, transform_m):
# Parses an expression from the tokens in Kconfig._tokens using a
@@ -2574,6 +2495,161 @@ class Kconfig(object):
#
+ # Post-parsing menu tree processing, including dependency propagation and
+ # implicit submenu creation
+ #
+
+ def _finalize_tree(self, node, visible_if):
+ # Propagates properties and dependencies, creates implicit menus (see
+ # kconfig-language.txt), removes 'if' nodes, and finalizes choices.
+ # This pretty closely mirrors menu_finalize() from the C
+ # implementation, with some minor tweaks (MenuNode holds lists of
+ # properties instead of each property having a MenuNode pointer, for
+ # example).
+ #
+ # node:
+ # The current "parent" menu node, from which we propagate
+ # dependencies
+ #
+ # visible_if:
+ # Dependencies from 'visible if' on parent menus. These are added to
+ # the prompts of symbols and choices.
+
+ if node.list:
+ # The menu node is a choice, menu, or if. Finalize each child in
+ # it.
+
+ if node.item == MENU:
+ visible_if = self._make_and(visible_if, node.visibility)
+
+ self._propagate_deps(node, visible_if)
+
+ cur = node.list
+ while cur:
+ self._finalize_tree(cur, visible_if)
+ cur = cur.next
+
+ elif isinstance(node.item, Symbol):
+ # The menu node is a symbol. See if we can create an implicit menu
+ # rooted at it and finalize each child in that menu if so, like for
+ # the choice/menu/if case above.
+ cur = node
+ while cur.next and _auto_menu_dep(node, cur.next):
+ # This also makes implicit submenu creation work recursively,
+ # with implicit menus inside implicit menus
+ self._finalize_tree(cur.next, visible_if)
+ cur = cur.next
+ cur.parent = node
+
+ if cur is not node:
+ # Found symbols that should go in an implicit submenu. Tilt
+ # them up above us.
+ node.list = node.next
+ node.next = cur.next
+ cur.next = None
+
+
+ if node.list:
+ # We have a parent node with individually finalized child nodes. Do
+ # final steps to finalize this "level" in the menu tree.
+ _flatten(node.list)
+ _remove_ifs(node)
+
+ # Empty choices (node.list None) are possible, so this needs to go
+ # outside
+ if isinstance(node.item, Choice):
+ _finalize_choice(node)
+
+ def _propagate_deps(self, node, visible_if):
+ # This function combines two tasks:
+ #
+ # 1) Copy properties from menu nodes to symbols and choices
+ #
+ # 2) Propagate dependencies from 'if' and 'depends on' to all
+ # properties
+ #
+ # See _parse_properties() as well.
+
+ # If the parent node holds a Choice, we use the Choice itself as the
+ # parent dependency. This makes sense as the value (mode) of the choice
+ # limits the visibility of the contained choice symbols. The C
+ # implementation works the same way.
+ #
+ # Due to the similar interface, Choice works as a drop-in replacement
+ # for Symbol here.
+ basedep = node.item if isinstance(node.item, Choice) else node.dep
+
+ cur = node.list
+ while cur:
+ cur.dep = dep = self._make_and(cur.dep, basedep)
+
+ # Propagate dependencies to prompt
+ if cur.prompt:
+ cur.prompt = (cur.prompt[0],
+ self._make_and(cur.prompt[1], dep))
+
+ if isinstance(cur.item, (Symbol, Choice)):
+ sc = cur.item
+
+ # See the Symbol class docstring
+ sc.direct_dep = self._make_or(sc.direct_dep, dep)
+
+ # TODO: Profile this code and see if the 'if's are worthwhile.
+ # Another potential optimization would be to assign the lists
+ # from the MenuNode directly instead of using extend() in cases
+ # where a symbol/choice only has a single MenuNode (the
+ # majority of cases).
+
+ # Propagate 'visible if' dependencies to the prompt
+ if cur.prompt:
+ cur.prompt = (cur.prompt[0],
+ self._make_and(cur.prompt[1], visible_if))
+
+ # Propagate dependencies to defaults
+
+ if cur.defaults:
+ cur.defaults = [(default, self._make_and(cond, dep))
+ for default, cond in cur.defaults]
+ sc.defaults.extend(cur.defaults)
+
+ # Propagate dependencies to ranges
+
+ if cur.ranges:
+ cur.ranges = [(low, high, self._make_and(cond, dep))
+ for low, high, cond in cur.ranges]
+ sc.ranges.extend(cur.ranges)
+
+ # Propagate dependencies to selects
+
+ if cur.selects:
+ cur.selects = [(target, self._make_and(cond, dep))
+ for target, cond in cur.selects]
+ sc.selects.extend(cur.selects)
+
+ # Modify the reverse dependencies of the selected symbol
+ for target, cond in cur.selects:
+ target.rev_dep = self._make_or(
+ target.rev_dep,
+ self._make_and(sc, cond))
+
+ # Propagate dependencies to implies
+
+ if cur.implies:
+ cur.implies = [(target, self._make_and(cond, dep))
+ for target, cond in cur.implies]
+ sc.implies.extend(cur.implies)
+
+ # Modify the weak reverse dependencies of the implied
+ # symbol
+ for target, cond in cur.implies:
+ target.weak_rev_dep = self._make_or(
+ target.weak_rev_dep,
+ self._make_and(sc, cond))
+
+
+ cur = cur.next
+
+ #
# Misc.
#
@@ -3280,18 +3356,16 @@ class Symbol(object):
def __str__(self):
"""
Returns a string representation of the symbol when it is printed,
- matching the Kconfig format. Prompts and help texts are included,
- though they really belong to the symbol's menu nodes rather than the
- symbol itself.
+ matching the Kconfig format, with parent dependencies propagated.
- The output is designed so that feeding it back to a Kconfig parser
- redefines the symbol as is. This also works for symbols defined in
- multiple locations, where all the definitions are output. See the
- module documentation for a small gotcha related to choice symbols.
+ The string is constructed by joining the strings returned by
+ MenuNode.__str__() for each of the symbol's menu nodes, so symbols
+ defined in multiple locations will return a string with all
+ definitions.
An empty string is returned for undefined and constant symbols.
"""
- return _sym_choice_str(self)
+ return "\n".join(str(node) for node in self.nodes)
#
# Private methods
@@ -3836,12 +3910,11 @@ class Choice(object):
"""
Returns a string representation of the choice when it is printed,
matching the Kconfig format (though without the contained choice
- symbols). Prompts and help texts are included, though they really
- belong to the choice's menu nodes rather than the choice itself.
+ symbols).
See Symbol.__str__() as well.
"""
- return _sym_choice_str(self)
+ return "\n".join(str(node) for node in self.nodes)
#
# Private methods
@@ -3984,6 +4057,24 @@ class MenuNode(object):
the Symbol or Choice instance. For menus and comments, the prompt holds
the text.
+ defaults:
+ The 'default' properties for this particular menu node. See
+ symbol.defaults.
+
+ When evaluating defaults, you should use Symbol/Choice.defaults instead,
+ as it include properties from all menu nodes (a symbol/choice can have
+ multiple definition locations/menu nodes). MenuNode.defaults is meant for
+ documentation generation.
+
+ selects:
+ Like MenuNode.defaults, for selects.
+
+ implies:
+ Like MenuNode.defaults, for implies.
+
+ ranges:
+ Like MenuNode.defaults, for ranges.
+
help:
The help text for the menu node for Symbols and Choices. None if there is
no help text. Always stored in the node rather than the Symbol or Choice.
@@ -3996,9 +4087,9 @@ class MenuNode(object):
attribute, and this attribute is then in turn propagated to the
properties of symbols and choices.
- If a symbol is defined in multiple locations, only the properties defined
- at a particular location get the corresponding MenuNode.dep dependencies
- propagated to them.
+ If a symbol or choice is defined in multiple locations, only the
+ properties defined at a particular location get the corresponding
+ MenuNode.dep dependencies propagated to them.
visibility:
The 'visible if' dependencies for the menu node (which must represent a
@@ -4040,6 +4131,12 @@ class MenuNode(object):
"parent",
"prompt",
"visibility",
+
+ # Properties
+ "defaults",
+ "selects",
+ "implies",
+ "ranges"
)
def __repr__(self):
@@ -4101,30 +4198,105 @@ class MenuNode(object):
def __str__(self):
"""
- Returns a string representation of the MenuNode, matching the Kconfig
+ Returns a string representation of the menu node, matching the Kconfig
format.
- For Symbol and Choice menu nodes, this function simply calls through to
- MenuNode.item.__str__(). For MENU and COMMENT nodes, a Kconfig-like
- representation of the menu or comment is returned.
+ The output could (almost) be fed back into a Kconfig parser to redefine
+ the object associated with the menu node. See the module documentation
+ for a gotcha related to choice symbols.
+
+ For symbols and choices with multiple menu nodes (multiple definition
+ locations), properties that aren't associated with a particular menu
+ node are shown on all menu nodes ('option env=...', 'optional' for
+ choices, etc.).
"""
+
+ return self._menu_comment_node_str() \
+ if self.item in (MENU, COMMENT) else \
+ self._sym_choice_node_str()
+
+ def _menu_comment_node_str(self):
+ s = '{} "{}"\n'.format("menu" if self.item == MENU else "comment",
+ self.prompt[0])
+
+ if self.dep is not self.kconfig.y:
+ s += "\tdepends on {}\n".format(expr_str(self.dep))
+
+ if self.item == MENU and self.visibility is not self.kconfig.y:
+ s += "\tvisible if {}\n".format(expr_str(self.visibility))
+
+ return s
+
+ def _sym_choice_node_str(self):
+ lines = []
+
+ def indent_add(s):
+ lines.append("\t" + s)
+
+ def indent_add_cond(s, cond):
+ if cond is not self.kconfig.y:
+ s += " if " + expr_str(cond)
+ indent_add(s)
+
if isinstance(self.item, (Symbol, Choice)):
- return self.item.__str__()
+ sc = self.item
+
+ if isinstance(sc, Symbol):
+ lines.append(
+ ("menuconfig " if self.is_menuconfig else "config ")
+ + sc.name)
+ else:
+ lines.append(
+ "choice" if sc.name is None else "choice " + sc.name)
+
+ if sc.orig_type != UNKNOWN:
+ indent_add(TYPE_TO_STR[sc.orig_type])
+
+ if self.prompt:
+ indent_add_cond(
+ 'prompt "{}"'.format(escape(self.prompt[0])),
+ self.prompt[1])
+
+ if isinstance(sc, Symbol):
+ if sc.is_allnoconfig_y:
+ indent_add("option allnoconfig_y")
+
+ if sc is sc.kconfig.defconfig_list:
+ indent_add("option defconfig_list")
+
+ if sc.env_var is not None:
+ indent_add('option env="{}"'.format(sc.env_var))
+
+ if sc is sc.kconfig.modules:
+ indent_add("option modules")
- if self.item in (MENU, COMMENT):
- s = ("menu" if self.item == MENU else "comment") + \
- ' "{}"\n'.format(escape(self.prompt[0]))
+ for low, high, cond in self.ranges:
+ indent_add_cond(
+ "range {} {}".format(expr_str(low), expr_str(high)),
+ cond)
- if self.dep is not self.kconfig.y:
- s += "\tdepends on {}\n".format(expr_str(self.dep))
+ for default, cond in self.defaults:
+ indent_add_cond("default " + expr_str(default), cond)
+
+ if isinstance(sc, Choice) and sc.is_optional:
+ indent_add("optional")
+
+ if isinstance(sc, Symbol):
+ for select, cond in self.selects:
+ indent_add_cond("select " + expr_str(select), cond)
+
+ for imply, cond in self.implies:
+ indent_add_cond("imply " + expr_str(imply), cond)
- if self.item == MENU and self.visibility is not self.kconfig.y:
- s += "\tvisible if {}\n".format(expr_str(self.visibility))
+ if self.dep is not sc.kconfig.y:
+ indent_add("depends on " + expr_str(self.dep))
- return s
+ if self.help is not None:
+ indent_add("help")
+ for line in self.help.splitlines():
+ indent_add(" " + line)
- # 'if' node. Should never appear in the final tree.
- return "if " + expr_str(self.dep)
+ return "\n".join(lines) + "\n"
class KconfigSyntaxError(Exception):
"""
@@ -4430,110 +4602,6 @@ def _decoding_error(e, filename):
e.object[e.start:e.end],
e.reason))
-
-# Printing functions
-
-def _sym_choice_str(sc):
- # Symbol/choice __str__() implementation. These have many properties in
- # common, so it makes sense to handle them together.
-
- lines = []
-
- def indent_add(s):
- lines.append("\t" + s)
-
- # We print the prompt(s) and help text(s) too as a convenience, even though
- # they're actually part of the MenuNode. If a symbol or choice is defined
- # in multiple locations (has more than one MenuNode), we output one
- # statement for each location, and print all the properties that belong to
- # the symbol/choice itself only at the first location. This gives output
- # that would function if fed to a Kconfig parser, even for such
- # symbols/choices (choices defined in multiple locations gets a bit iffy
- # since they also have child nodes, though I've never seen such a choice).
-
- if not sc.nodes:
- return ""
-
- for node in sc.nodes:
- if isinstance(sc, Symbol):
- if node.is_menuconfig:
- lines.append("menuconfig " + sc.name)
- else:
- lines.append("config " + sc.name)
- else:
- if sc.name is None:
- lines.append("choice")
- else:
- lines.append("choice " + sc.name)
-
- if node is sc.nodes[0] and sc.orig_type != UNKNOWN:
- indent_add(TYPE_TO_STR[sc.orig_type])
-
- if node.prompt:
- prompt, cond = node.prompt
- prompt_str = 'prompt "{}"'.format(escape(prompt))
- if cond is not sc.kconfig.y:
- prompt_str += " if " + expr_str(cond)
- indent_add(prompt_str)
-
- if node is sc.nodes[0]:
- if isinstance(sc, Symbol):
- if sc.is_allnoconfig_y:
- indent_add("option allnoconfig_y")
-
- if sc is sc.kconfig.defconfig_list:
- indent_add("option defconfig_list")
-
- if sc.env_var is not None:
- indent_add('option env="{}"'.format(sc.env_var))
-
- if sc is sc.kconfig.modules:
- indent_add("option modules")
-
- if isinstance(sc, Symbol):
- for low, high, cond in sc.ranges:
- range_string = "range {} {}" \
- .format(expr_str(low), expr_str(high))
- if cond is not sc.kconfig.y:
- range_string += " if " + expr_str(cond)
- indent_add(range_string)
-
- for default, cond in sc.defaults:
- default_string = "default " + expr_str(default)
- if cond is not sc.kconfig.y:
- default_string += " if " + expr_str(cond)
- indent_add(default_string)
-
- if isinstance(sc, Choice) and sc.is_optional:
- indent_add("optional")
-
- if isinstance(sc, Symbol):
- for select, cond in sc.selects:
- select_string = "select " + expr_str(select)
- if cond is not sc.kconfig.y:
- select_string += " if " + expr_str(cond)
- indent_add(select_string)
-
- for imply, cond in sc.implies:
- imply_string = "imply " + expr_str(imply)
- if cond is not sc.kconfig.y:
- imply_string += " if " + expr_str(cond)
- indent_add(imply_string)
-
- if node.dep is not sc.kconfig.y:
- indent_add("depends on " + expr_str(node.dep))
-
- if node.help is not None:
- indent_add("help")
- for line in node.help.splitlines():
- indent_add(" " + line)
-
- # Add a blank line if there are more nodes to print
- if node is not sc.nodes[-1]:
- lines.append("")
-
- return "\n".join(lines) + "\n"
-
def _name_and_loc(sc):
# Helper for giving the symbol/choice name and location(s) in e.g. warnings
@@ -4652,50 +4720,6 @@ def _finalize_choice(node):
if sym.orig_type == UNKNOWN:
sym.orig_type = choice.orig_type
-def _finalize_tree(node):
- # Creates implicit menus from dependencies (see kconfig-language.txt),
- # removes 'if' nodes, and finalizes choices. This pretty closely mirrors
- # menu_finalize() from the C implementation, though we propagate
- # dependencies during parsing instead.
-
- if node.list:
- # The menu node is a choice, menu, or if. Finalize each child in it.
- cur = node.list
- while cur:
- _finalize_tree(cur)
- cur = cur.next
-
- elif isinstance(node.item, Symbol):
- # The menu node is a symbol. See if we can create an implicit menu
- # rooted at it and finalize each child in that menu if so, like for the
- # choice/menu/if case above.
- cur = node
- while cur.next and _auto_menu_dep(node, cur.next):
- # This also makes implicit submenu creation work recursively, with
- # implicit menus inside implicit menus
- _finalize_tree(cur.next)
- cur = cur.next
- cur.parent = node
-
- if cur is not node:
- # Found symbols that should go in an implicit submenu. Tilt them up
- # above us.
- node.list = node.next
- node.next = cur.next
- cur.next = None
-
-
- if node.list:
- # We have a node with child nodes where the child nodes are now
- # individually finalized. Do final steps to finalize this "level" in
- # the menu tree.
- _flatten(node.list)
- _remove_ifs(node)
-
- # Empty choices (node.list None) are possible, so this needs to go outside
- if isinstance(node.item, Choice):
- _finalize_choice(node)
-
def _check_sym_sanity(sym):
# Checks various symbol properties that are handiest to check after
# parsing. Only generates errors and warnings.