Kconfig: Support macro expansion within symbol names
Update Kconfiglib to upstream revision 2be02fac78527 to add support for expanding macros within symbol names, extending the existing Kconfig preprocessor (https://github.com/torvalds/linux/blob/master/Documentation/kbuild/ kconfig-macro-language.txt). Some minor optimizations are included as well. This makes it possible to add Kconfig templates to avoid code repetition, e.g. like below: Kconfig.log_template: choice prompt "Max compiled-in log level for $(module-str)" config $(module)_LOG_LEVEL_OFF bool "Off" config $(module)_LOG_LEVEL_ERR bool "Error" config $(module)_LOG_LEVEL_WRN bool "Warning" config $(module)_LOG_LEVEL_INF bool "Info" config $(module)_LOG_LEVEL_DBG bool "Debug" endchoice config $(module)_LOG_LEVEL int default 0 if $(module)_LOG_LEVEL_OFF default 1 if $(module)_LOG_LEVEL_ERR default 2 if $(module)_LOG_LEVEL_WRN default 3 if $(module)_LOG_LEVEL_INF default 4 if $(module)_LOG_LEVEL_DBG Using the template: module = FOO module-str = foo source "Kconfig.log_template" ... module = BAR module-str = bar source "Kconfig.log_template" This feature might create harder-to-read Kconfig files if abused, so it should probably be used sparingly. Fixes: #9761 Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
This commit is contained in:
parent
ced1c03c40
commit
213a88f7ff
1 changed files with 161 additions and 123 deletions
|
@ -971,9 +971,9 @@ class Kconfig(object):
|
|||
if sym.orig_type in (BOOL, TRISTATE):
|
||||
# The C implementation only checks the first character
|
||||
# to the right of '=', for whatever reason
|
||||
if not ((sym.orig_type == BOOL and
|
||||
if not ((sym.orig_type is BOOL and
|
||||
val.startswith(("n", "y"))) or \
|
||||
(sym.orig_type == TRISTATE and
|
||||
(sym.orig_type is TRISTATE and
|
||||
val.startswith(("n", "m", "y")))):
|
||||
self._warn("'{}' is not a valid value for the {} "
|
||||
"symbol {}. Assignment ignored."
|
||||
|
@ -1000,7 +1000,7 @@ class Kconfig(object):
|
|||
# Set the choice's mode
|
||||
sym.choice.set_value(val)
|
||||
|
||||
elif sym.orig_type == STRING:
|
||||
elif sym.orig_type is STRING:
|
||||
match = _conf_string_match(val)
|
||||
if not match:
|
||||
self._warn("malformed string literal in "
|
||||
|
@ -1102,13 +1102,13 @@ class Kconfig(object):
|
|||
.format(self.config_prefix, sym.name,
|
||||
"_MODULE" if val == "m" else ""))
|
||||
|
||||
elif sym.orig_type == STRING:
|
||||
elif sym.orig_type is STRING:
|
||||
f.write('#define {}{} "{}"\n'
|
||||
.format(self.config_prefix, sym.name,
|
||||
escape(val)))
|
||||
|
||||
elif sym.orig_type in (INT, HEX):
|
||||
if sym.orig_type == HEX and \
|
||||
if sym.orig_type is HEX and \
|
||||
not val.startswith(("0x", "0X")):
|
||||
val = "0x" + val
|
||||
|
||||
|
@ -1152,8 +1152,8 @@ class Kconfig(object):
|
|||
f.write(item.config_string)
|
||||
|
||||
elif expr_value(node.dep) and \
|
||||
((item == MENU and expr_value(node.visibility)) or
|
||||
item == COMMENT):
|
||||
((item is MENU and expr_value(node.visibility)) or
|
||||
item is COMMENT):
|
||||
|
||||
f.write("\n#\n# {}\n#\n".format(node.prompt[0]))
|
||||
|
||||
|
@ -1200,7 +1200,7 @@ class Kconfig(object):
|
|||
if sym.choice and \
|
||||
not sym.choice.is_optional and \
|
||||
sym.choice._get_selection_from_defaults() is sym and \
|
||||
sym.orig_type == BOOL and \
|
||||
sym.orig_type is BOOL and \
|
||||
sym.tri_value == 2:
|
||||
continue
|
||||
|
||||
|
@ -1366,7 +1366,7 @@ class Kconfig(object):
|
|||
if name in self.syms:
|
||||
sym = self.syms[name]
|
||||
|
||||
if sym.orig_type == STRING:
|
||||
if sym.orig_type is STRING:
|
||||
match = _conf_string_match(val)
|
||||
if not match:
|
||||
continue
|
||||
|
@ -1771,9 +1771,6 @@ class Kconfig(object):
|
|||
if match:
|
||||
# We have an identifier or keyword
|
||||
|
||||
# Jump past it
|
||||
i = match.end()
|
||||
|
||||
# Check what it is. lookup_sym() will take care of allocating
|
||||
# new symbols for us the first time we see them. Note that
|
||||
# 'token' still refers to the previous token.
|
||||
|
@ -1783,11 +1780,20 @@ class Kconfig(object):
|
|||
if keyword:
|
||||
# It's a keyword
|
||||
token = keyword
|
||||
# Jump past it
|
||||
i = match.end()
|
||||
|
||||
elif token not in _STRING_LEX:
|
||||
# It's a non-const symbol, except we translate n, m, and y
|
||||
# into the corresponding constant symbols, like the C
|
||||
# implementation
|
||||
|
||||
if "$" in name:
|
||||
# Macro expansion within symbol name
|
||||
name, s, i = self._expand_name(s, i)
|
||||
else:
|
||||
i = match.end()
|
||||
|
||||
token = self.const_syms[name] \
|
||||
if name in ("n", "m", "y") else \
|
||||
self._lookup_sym(name)
|
||||
|
@ -1803,17 +1809,17 @@ class Kconfig(object):
|
|||
#
|
||||
# endmenu
|
||||
token = name
|
||||
i = match.end()
|
||||
|
||||
else:
|
||||
# Neither a keyword nor a non-const symbol (except
|
||||
# $()-expansion might still yield a non-const symbol).
|
||||
# Neither a keyword nor a non-const symbol
|
||||
|
||||
# We always strip whitespace after tokens, so it is safe to
|
||||
# assume that s[i] is the start of a token here.
|
||||
c = s[i]
|
||||
|
||||
if c in "\"'":
|
||||
s, end_i = self._expand_str(s, i, c)
|
||||
s, end_i = self._expand_str(s, i)
|
||||
|
||||
# os.path.expandvars() and the $UNAME_RELEASE replace() is
|
||||
# a backwards compatibility hack, which should be
|
||||
|
@ -1833,7 +1839,7 @@ class Kconfig(object):
|
|||
# refer to a constant symbol named "FOO".
|
||||
token = val \
|
||||
if token in _STRING_LEX or \
|
||||
tokens[0] == _T_OPTION else \
|
||||
tokens[0] is _T_OPTION else \
|
||||
self._lookup_const_sym(val)
|
||||
|
||||
elif s.startswith("&&", i):
|
||||
|
@ -1864,23 +1870,6 @@ class Kconfig(object):
|
|||
token = _T_CLOSE_PAREN
|
||||
i += 1
|
||||
|
||||
elif s.startswith("$(", i):
|
||||
s, end_i = self._expand_macro(s, i, ())
|
||||
val = s[i:end_i]
|
||||
# isspace() is False for empty strings
|
||||
if not val.strip():
|
||||
# Avoid creating a Kconfig symbol with a blank name.
|
||||
# It's almost guaranteed to be an error.
|
||||
self._parse_error("macro expanded to blank string")
|
||||
i = end_i
|
||||
|
||||
# Compatibility with what the C implementation does. Might
|
||||
# be unexpected that you can reference non-constant symbols
|
||||
# this way though...
|
||||
token = self.const_syms[val] \
|
||||
if val in ("n", "m", "y") else \
|
||||
self._lookup_sym(val)
|
||||
|
||||
elif c == "#":
|
||||
break
|
||||
|
||||
|
@ -1997,7 +1986,7 @@ class Kconfig(object):
|
|||
def _check_token(self, token):
|
||||
# If the next token is 'token', removes it and returns True
|
||||
|
||||
if self._tokens[self._tokens_i + 1] == token:
|
||||
if self._tokens[self._tokens_i + 1] is token:
|
||||
self._tokens_i += 1
|
||||
return True
|
||||
return False
|
||||
|
@ -2083,13 +2072,49 @@ class Kconfig(object):
|
|||
s, i = self._expand_macro(s, i, args)
|
||||
return s
|
||||
|
||||
def _expand_str(self, s, i, quote):
|
||||
def _expand_name(self, s, i):
|
||||
# Expands a symbol name starting at index 'i' in 's'.
|
||||
#
|
||||
# Returns the expanded name, the expanded 's' (including the part
|
||||
# before the name), and the index of the first character in the next
|
||||
# token after the name.
|
||||
|
||||
s, end_i = self._expand_name_iter(s, i)
|
||||
name = s[i:end_i]
|
||||
# isspace() is False for empty strings
|
||||
if not name.strip():
|
||||
# Avoid creating a Kconfig symbol with a blank name. It's almost
|
||||
# guaranteed to be an error.
|
||||
self._parse_error("macro expanded to blank string")
|
||||
|
||||
# Skip trailing whitespace
|
||||
while end_i < len(s) and s[end_i].isspace():
|
||||
end_i += 1
|
||||
|
||||
return name, s, end_i
|
||||
|
||||
def _expand_name_iter(self, s, i):
|
||||
# Expands a symbol name starting at index 'i' in 's'.
|
||||
#
|
||||
# Returns the expanded 's' (including the part before the name) and the
|
||||
# index of the first character after the expanded name in 's'.
|
||||
|
||||
while 1:
|
||||
match = _name_special_search(s, i)
|
||||
|
||||
if match.group() == "$(":
|
||||
s, i = self._expand_macro(s, match.start(), ())
|
||||
else:
|
||||
return (s, match.start())
|
||||
|
||||
def _expand_str(self, s, i):
|
||||
# Expands a quoted string starting at index 'i' in 's'. Handles both
|
||||
# backslash escapes and macro expansion.
|
||||
#
|
||||
# Returns the expanded 's' (including the part before the string) and
|
||||
# the index of the first character after the expanded string in 's'.
|
||||
|
||||
quote = s[i]
|
||||
i += 1 # Skip over initial "/'
|
||||
while 1:
|
||||
match = _string_special_search(s, i)
|
||||
|
@ -2294,7 +2319,7 @@ class Kconfig(object):
|
|||
node = MenuNode()
|
||||
node.kconfig = self
|
||||
node.item = sym
|
||||
node.is_menuconfig = (t0 == _T_MENUCONFIG)
|
||||
node.is_menuconfig = (t0 is _T_MENUCONFIG)
|
||||
node.prompt = node.help = node.list = None
|
||||
node.parent = parent
|
||||
node.filename = self._filename
|
||||
|
@ -2353,13 +2378,13 @@ class Kconfig(object):
|
|||
|
||||
self._leave_file()
|
||||
|
||||
elif t0 == end_token:
|
||||
elif t0 is end_token:
|
||||
# We have reached the end of the block. Terminate the final
|
||||
# node and return it.
|
||||
prev.next = None
|
||||
return prev
|
||||
|
||||
elif t0 == _T_IF:
|
||||
elif t0 is _T_IF:
|
||||
node = MenuNode()
|
||||
node.item = node.prompt = None
|
||||
node.parent = parent
|
||||
|
@ -2373,7 +2398,7 @@ class Kconfig(object):
|
|||
|
||||
prev.next = prev = node
|
||||
|
||||
elif t0 == _T_MENU:
|
||||
elif t0 is _T_MENU:
|
||||
node = MenuNode()
|
||||
node.kconfig = self
|
||||
node.item = MENU
|
||||
|
@ -2393,7 +2418,7 @@ class Kconfig(object):
|
|||
|
||||
prev.next = prev = node
|
||||
|
||||
elif t0 == _T_COMMENT:
|
||||
elif t0 is _T_COMMENT:
|
||||
node = MenuNode()
|
||||
node.kconfig = self
|
||||
node.item = COMMENT
|
||||
|
@ -2411,7 +2436,7 @@ class Kconfig(object):
|
|||
|
||||
prev.next = prev = node
|
||||
|
||||
elif t0 == _T_CHOICE:
|
||||
elif t0 is _T_CHOICE:
|
||||
if self._peek_token() is None:
|
||||
choice = Choice()
|
||||
choice.direct_dep = self.n
|
||||
|
@ -2449,7 +2474,7 @@ class Kconfig(object):
|
|||
|
||||
prev.next = prev = node
|
||||
|
||||
elif t0 == _T_MAINMENU:
|
||||
elif t0 is _T_MAINMENU:
|
||||
self.top_node.prompt = (self._expect_str_and_eol(), self.y)
|
||||
self.top_node.filename = self._filename
|
||||
self.top_node.linenr = self._linenr
|
||||
|
@ -2502,31 +2527,31 @@ class Kconfig(object):
|
|||
if self._peek_token() is not None:
|
||||
self._parse_prompt(node)
|
||||
|
||||
elif t0 == _T_DEPENDS:
|
||||
elif t0 is _T_DEPENDS:
|
||||
if not self._check_token(_T_ON):
|
||||
self._parse_error('expected "on" after "depends"')
|
||||
|
||||
node.dep = self._make_and(node.dep,
|
||||
self._expect_expr_and_eol())
|
||||
|
||||
elif t0 == _T_HELP:
|
||||
elif t0 is _T_HELP:
|
||||
self._parse_help(node)
|
||||
|
||||
elif t0 == _T_SELECT:
|
||||
elif t0 is _T_SELECT:
|
||||
if not isinstance(node.item, Symbol):
|
||||
self._parse_error("only symbols can select")
|
||||
|
||||
node.selects.append((self._expect_nonconst_sym(),
|
||||
self._parse_cond()))
|
||||
|
||||
elif t0 == _T_IMPLY:
|
||||
elif t0 is _T_IMPLY:
|
||||
if not isinstance(node.item, Symbol):
|
||||
self._parse_error("only symbols can imply")
|
||||
|
||||
node.implies.append((self._expect_nonconst_sym(),
|
||||
self._parse_cond()))
|
||||
|
||||
elif t0 == _T_DEFAULT:
|
||||
elif t0 is _T_DEFAULT:
|
||||
node.defaults.append((self._parse_expr(False),
|
||||
self._parse_cond()))
|
||||
|
||||
|
@ -2536,15 +2561,15 @@ class Kconfig(object):
|
|||
node.defaults.append((self._parse_expr(False),
|
||||
self._parse_cond()))
|
||||
|
||||
elif t0 == _T_PROMPT:
|
||||
elif t0 is _T_PROMPT:
|
||||
self._parse_prompt(node)
|
||||
|
||||
elif t0 == _T_RANGE:
|
||||
elif t0 is _T_RANGE:
|
||||
node.ranges.append((self._expect_sym(),
|
||||
self._expect_sym(),
|
||||
self._parse_cond()))
|
||||
|
||||
elif t0 == _T_OPTION:
|
||||
elif t0 is _T_OPTION:
|
||||
if self._check_token(_T_ENV):
|
||||
if not self._check_token(_T_EQUAL):
|
||||
self._parse_error('expected "=" after "env"')
|
||||
|
@ -2609,14 +2634,14 @@ class Kconfig(object):
|
|||
else:
|
||||
self._parse_error("unrecognized option")
|
||||
|
||||
elif t0 == _T_VISIBLE:
|
||||
elif t0 is _T_VISIBLE:
|
||||
if not self._check_token(_T_IF):
|
||||
self._parse_error('expected "if" after "visible"')
|
||||
|
||||
node.visibility = self._make_and(node.visibility,
|
||||
self._expect_expr_and_eol())
|
||||
|
||||
elif t0 == _T_OPTIONAL:
|
||||
elif t0 is _T_OPTIONAL:
|
||||
if not isinstance(node.item, Choice):
|
||||
self._parse_error('"optional" is only valid for choices')
|
||||
|
||||
|
@ -2791,11 +2816,11 @@ class Kconfig(object):
|
|||
# EQUAL, UNEQUAL, etc., so we can just use the token directly
|
||||
return (self._next_token(), token, self._expect_sym())
|
||||
|
||||
if token == _T_NOT:
|
||||
if token is _T_NOT:
|
||||
# token == _T_NOT == NOT
|
||||
return (token, self._parse_factor(transform_m))
|
||||
|
||||
if token == _T_OPEN_PAREN:
|
||||
if token is _T_OPEN_PAREN:
|
||||
expr_parse = self._parse_expr(transform_m)
|
||||
if self._check_token(_T_CLOSE_PAREN):
|
||||
return expr_parse
|
||||
|
@ -2917,7 +2942,7 @@ class Kconfig(object):
|
|||
# The menu node is a choice, menu, or if. Finalize each child in
|
||||
# it.
|
||||
|
||||
if node.item == MENU:
|
||||
if node.item is MENU:
|
||||
visible_if = self._make_and(visible_if, node.visibility)
|
||||
|
||||
# Propagate the menu node's dependencies to each child menu node.
|
||||
|
@ -3415,7 +3440,7 @@ class Symbol(object):
|
|||
"""
|
||||
See the class documentation.
|
||||
"""
|
||||
if self.orig_type == TRISTATE and \
|
||||
if self.orig_type is TRISTATE and \
|
||||
((self.choice and self.choice.tri_value == 2) or
|
||||
not self.kconfig.modules.tri_value):
|
||||
return BOOL
|
||||
|
@ -3438,7 +3463,7 @@ class Symbol(object):
|
|||
# As a quirk of Kconfig, undefined symbols get their name as their
|
||||
# string value. This is why things like "FOO = bar" work for seeing if
|
||||
# FOO has the value "bar".
|
||||
if self.orig_type == UNKNOWN:
|
||||
if self.orig_type is UNKNOWN:
|
||||
self._cached_str_val = self.name
|
||||
return self.name
|
||||
|
||||
|
@ -3528,7 +3553,7 @@ class Symbol(object):
|
|||
# The value is rewritten to a standard form if it is
|
||||
# clamped
|
||||
val = str(clamp) \
|
||||
if self.orig_type == INT else \
|
||||
if self.orig_type is INT else \
|
||||
hex(clamp)
|
||||
|
||||
if has_default:
|
||||
|
@ -3540,7 +3565,7 @@ class Symbol(object):
|
|||
num2str(clamp), num2str(low),
|
||||
num2str(high)))
|
||||
|
||||
elif self.orig_type == STRING:
|
||||
elif self.orig_type is STRING:
|
||||
if vis and self.user_value is not None:
|
||||
# If the symbol is visible and has a user value, use that
|
||||
val = self.user_value
|
||||
|
@ -3572,7 +3597,7 @@ class Symbol(object):
|
|||
return self._cached_tri_val
|
||||
|
||||
if self.orig_type not in (BOOL, TRISTATE):
|
||||
if self.orig_type != UNKNOWN:
|
||||
if self.orig_type is not UNKNOWN:
|
||||
# Would take some work to give the location here
|
||||
self.kconfig._warn(
|
||||
"The {} symbol {} is being evaluated in a logical context "
|
||||
|
@ -3627,7 +3652,7 @@ class Symbol(object):
|
|||
# m is promoted to y for (1) bool symbols and (2) symbols with a
|
||||
# weak_rev_dep (from imply) of y
|
||||
if val == 1 and \
|
||||
(self.type == BOOL or expr_value(self.weak_rev_dep) == 2):
|
||||
(self.type is BOOL or expr_value(self.weak_rev_dep) == 2):
|
||||
val = 2
|
||||
|
||||
elif vis == 2:
|
||||
|
@ -3685,7 +3710,7 @@ class Symbol(object):
|
|||
return "{}{}={}\n" \
|
||||
.format(self.kconfig.config_prefix, self.name, val)
|
||||
|
||||
if self.orig_type == STRING:
|
||||
if self.orig_type is STRING:
|
||||
return '{}{}="{}"\n' \
|
||||
.format(self.kconfig.config_prefix, self.name, escape(val))
|
||||
|
||||
|
@ -3740,12 +3765,12 @@ class Symbol(object):
|
|||
return True
|
||||
|
||||
# Check if the value is valid for our type
|
||||
if not (self.orig_type == BOOL and value in (0, 2, "n", "y") or
|
||||
self.orig_type == TRISTATE and value in (0, 1, 2, "n", "m", "y") or
|
||||
if not (self.orig_type is BOOL and value in (0, 2, "n", "y") or
|
||||
self.orig_type is TRISTATE and value in (0, 1, 2, "n", "m", "y") or
|
||||
(isinstance(value, str) and
|
||||
(self.orig_type == STRING or
|
||||
self.orig_type == INT and _is_base_n(value, 10) or
|
||||
self.orig_type == HEX and _is_base_n(value, 16)
|
||||
(self.orig_type is STRING or
|
||||
self.orig_type is INT and _is_base_n(value, 10) or
|
||||
self.orig_type is HEX and _is_base_n(value, 16)
|
||||
and int(value, 16) >= 0))):
|
||||
|
||||
# Display tristate values as n, m, y in the warning
|
||||
|
@ -3754,17 +3779,10 @@ class Symbol(object):
|
|||
"assignment ignored"
|
||||
.format(TRI_TO_STR[value] if value in (0, 1, 2) else
|
||||
"'{}'".format(value),
|
||||
_name_and_loc(self),
|
||||
TYPE_TO_STR[self.orig_type]))
|
||||
_name_and_loc(self), TYPE_TO_STR[self.orig_type]))
|
||||
|
||||
return False
|
||||
|
||||
if self.env_var is not None:
|
||||
self.kconfig._warn("ignored attempt to assign user value to "
|
||||
"{}, which is set from the environment"
|
||||
.format(_name_and_loc(self)))
|
||||
return False
|
||||
|
||||
if self.orig_type in (BOOL, TRISTATE) and value in ("n", "m", "y"):
|
||||
value = STR_TO_TRI[value]
|
||||
|
||||
|
@ -3954,7 +3972,7 @@ class Symbol(object):
|
|||
return (2,)
|
||||
|
||||
if not rev_dep_val:
|
||||
if self.type == BOOL or expr_value(self.weak_rev_dep) == 2:
|
||||
if self.type is BOOL or expr_value(self.weak_rev_dep) == 2:
|
||||
return (0, 2)
|
||||
return (0, 1, 2)
|
||||
|
||||
|
@ -3963,7 +3981,7 @@ class Symbol(object):
|
|||
|
||||
# rev_dep_val == 1
|
||||
|
||||
if self.type == BOOL or expr_value(self.weak_rev_dep) == 2:
|
||||
if self.type is BOOL or expr_value(self.weak_rev_dep) == 2:
|
||||
return (2,)
|
||||
return (1, 2)
|
||||
|
||||
|
@ -4063,7 +4081,7 @@ class Symbol(object):
|
|||
|
||||
# Transpose mod to yes if type is bool (possibly due to modules
|
||||
# being disabled)
|
||||
if val == 1 and self.type == BOOL:
|
||||
if val == 1 and self.type is BOOL:
|
||||
val = 2
|
||||
|
||||
return TRI_TO_STR[val]
|
||||
|
@ -4284,7 +4302,7 @@ class Choice(object):
|
|||
"""
|
||||
Returns the type of the choice. See Symbol.type.
|
||||
"""
|
||||
if self.orig_type == TRISTATE and not self.kconfig.modules.tri_value:
|
||||
if self.orig_type is TRISTATE and not self.kconfig.modules.tri_value:
|
||||
return BOOL
|
||||
|
||||
return self.orig_type
|
||||
|
@ -4314,7 +4332,7 @@ class Choice(object):
|
|||
val = min(val, self.visibility)
|
||||
|
||||
# Promote m to y for boolean choices
|
||||
return 2 if val == 1 and self.type == BOOL else val
|
||||
return 2 if val == 1 and self.type is BOOL else val
|
||||
|
||||
@property
|
||||
def assignable(self):
|
||||
|
@ -4365,8 +4383,8 @@ class Choice(object):
|
|||
self._was_set = True
|
||||
return True
|
||||
|
||||
if not ((self.orig_type == BOOL and value in (0, 2, "n", "y") ) or
|
||||
(self.orig_type == TRISTATE and value in (0, 1, 2, "n", "m", "y"))):
|
||||
if not ((self.orig_type is BOOL and value in (0, 2, "n", "y") ) or
|
||||
(self.orig_type is TRISTATE and value in (0, 1, 2, "n", "m", "y"))):
|
||||
|
||||
# Display tristate values as n, m, y in the warning
|
||||
self.kconfig._warn(
|
||||
|
@ -4515,8 +4533,8 @@ class Choice(object):
|
|||
|
||||
if vis == 2:
|
||||
if not self.is_optional:
|
||||
return (2,) if self.type == BOOL else (1, 2)
|
||||
return (0, 2) if self.type == BOOL else (0, 1, 2)
|
||||
return (2,) if self.type is BOOL else (1, 2)
|
||||
return (0, 2) if self.type is BOOL else (0, 1, 2)
|
||||
|
||||
# vis == 1
|
||||
|
||||
|
@ -4733,7 +4751,7 @@ class MenuNode(object):
|
|||
if self.prompt:
|
||||
res |= expr_items(self.prompt[1])
|
||||
|
||||
if self.item == MENU:
|
||||
if self.item is MENU:
|
||||
res |= expr_items(self.visibility)
|
||||
|
||||
for value, cond in self.defaults:
|
||||
|
@ -4771,10 +4789,10 @@ class MenuNode(object):
|
|||
s += " " + self.item.name
|
||||
fields.append(s)
|
||||
|
||||
elif self.item == MENU:
|
||||
elif self.item is MENU:
|
||||
fields.append("menu node for menu")
|
||||
|
||||
elif self.item == COMMENT:
|
||||
elif self.item is COMMENT:
|
||||
fields.append("menu node for comment")
|
||||
|
||||
elif self.item is None:
|
||||
|
@ -4794,7 +4812,7 @@ class MenuNode(object):
|
|||
|
||||
fields.append("deps " + TRI_TO_STR[expr_value(self.dep)])
|
||||
|
||||
if self.item == MENU:
|
||||
if self.item is MENU:
|
||||
fields.append("'visible if' deps " + \
|
||||
TRI_TO_STR[expr_value(self.visibility)])
|
||||
|
||||
|
@ -4837,13 +4855,13 @@ class MenuNode(object):
|
|||
self._sym_choice_node_str(sc_expr_str_fn)
|
||||
|
||||
def _menu_comment_node_str(self, sc_expr_str_fn):
|
||||
s = '{} "{}"\n'.format("menu" if self.item == MENU else "comment",
|
||||
s = '{} "{}"\n'.format("menu" if self.item is MENU else "comment",
|
||||
self.prompt[0])
|
||||
|
||||
if self.dep is not self.kconfig.y:
|
||||
s += "\tdepends on {}\n".format(expr_str(self.dep, sc_expr_str_fn))
|
||||
|
||||
if self.item == MENU and self.visibility is not self.kconfig.y:
|
||||
if self.item is MENU and self.visibility is not self.kconfig.y:
|
||||
s += "\tvisible if {}\n".format(expr_str(self.visibility,
|
||||
sc_expr_str_fn))
|
||||
|
||||
|
@ -4869,7 +4887,7 @@ class MenuNode(object):
|
|||
else:
|
||||
lines.append("choice " + sc.name if sc.name else "choice")
|
||||
|
||||
if sc.orig_type != UNKNOWN:
|
||||
if sc.orig_type is not UNKNOWN:
|
||||
indent_add(TYPE_TO_STR[sc.orig_type])
|
||||
|
||||
if self.prompt:
|
||||
|
@ -4986,18 +5004,18 @@ def expr_value(expr):
|
|||
if not isinstance(expr, tuple):
|
||||
return expr.tri_value
|
||||
|
||||
if expr[0] == AND:
|
||||
if expr[0] is AND:
|
||||
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, expr_value(expr[2]))
|
||||
|
||||
if expr[0] == OR:
|
||||
if expr[0] is OR:
|
||||
v1 = expr_value(expr[1])
|
||||
# Short-circuit the y case as an optimization
|
||||
return 2 if v1 == 2 else max(v1, expr_value(expr[2]))
|
||||
|
||||
if expr[0] == NOT:
|
||||
if expr[0] is NOT:
|
||||
return 2 - expr_value(expr[1])
|
||||
|
||||
if expr[0] in _RELATIONS:
|
||||
|
@ -5008,7 +5026,7 @@ def expr_value(expr):
|
|||
oper, op1, op2 = expr
|
||||
|
||||
# If both operands are strings...
|
||||
if op1.orig_type == STRING and op2.orig_type == STRING:
|
||||
if op1.orig_type is STRING and op2.orig_type is STRING:
|
||||
# ...then compare them lexicographically
|
||||
comp = _strcmp(op1.str_value, op2.str_value)
|
||||
else:
|
||||
|
@ -5020,12 +5038,12 @@ def expr_value(expr):
|
|||
# parse as numbers
|
||||
comp = _strcmp(op1.str_value, op2.str_value)
|
||||
|
||||
if oper == EQUAL: res = comp == 0
|
||||
elif oper == UNEQUAL: res = comp != 0
|
||||
elif oper == LESS: res = comp < 0
|
||||
elif oper == LESS_EQUAL: res = comp <= 0
|
||||
elif oper == GREATER: res = comp > 0
|
||||
elif oper == GREATER_EQUAL: res = comp >= 0
|
||||
if oper is EQUAL: res = comp == 0
|
||||
elif oper is UNEQUAL: res = comp != 0
|
||||
elif oper is LESS: res = comp < 0
|
||||
elif oper is LESS_EQUAL: res = comp <= 0
|
||||
elif oper is GREATER: res = comp > 0
|
||||
elif oper is GREATER_EQUAL: res = comp >= 0
|
||||
|
||||
return 2*res
|
||||
|
||||
|
@ -5066,17 +5084,17 @@ def expr_str(expr, sc_expr_str_fn=standard_sc_expr_str):
|
|||
if not isinstance(expr, tuple):
|
||||
return sc_expr_str_fn(expr)
|
||||
|
||||
if expr[0] == AND:
|
||||
if expr[0] is AND:
|
||||
return "{} && {}".format(_parenthesize(expr[1], OR, sc_expr_str_fn),
|
||||
_parenthesize(expr[2], OR, sc_expr_str_fn))
|
||||
|
||||
if expr[0] == OR:
|
||||
if expr[0] is OR:
|
||||
# This turns A && B || C && D into "(A && B) || (C && D)", which is
|
||||
# redundant, but more readable
|
||||
return "{} || {}".format(_parenthesize(expr[1], AND, sc_expr_str_fn),
|
||||
_parenthesize(expr[2], AND, sc_expr_str_fn))
|
||||
|
||||
if expr[0] == NOT:
|
||||
if expr[0] is NOT:
|
||||
if isinstance(expr[1], tuple):
|
||||
return "!({})".format(expr_str(expr[1], sc_expr_str_fn))
|
||||
return "!" + sc_expr_str_fn(expr[1]) # Symbol
|
||||
|
@ -5103,7 +5121,7 @@ def expr_items(expr):
|
|||
rec(subexpr[1])
|
||||
|
||||
# NOTs only have a single operand
|
||||
if subexpr[0] != NOT:
|
||||
if subexpr[0] is not NOT:
|
||||
rec(subexpr[2])
|
||||
|
||||
else:
|
||||
|
@ -5148,7 +5166,7 @@ def split_expr(expr, op):
|
|||
res = []
|
||||
|
||||
def rec(subexpr):
|
||||
if isinstance(subexpr, tuple) and subexpr[0] == op:
|
||||
if isinstance(subexpr, tuple) and subexpr[0] is op:
|
||||
rec(subexpr[1])
|
||||
rec(subexpr[2])
|
||||
else:
|
||||
|
@ -5214,18 +5232,18 @@ def _visibility(sc):
|
|||
vis = max(vis, expr_value(node.prompt[1]))
|
||||
|
||||
if isinstance(sc, Symbol) and sc.choice:
|
||||
if sc.choice.orig_type == TRISTATE and sc.orig_type != TRISTATE and \
|
||||
sc.choice.tri_value != 2:
|
||||
if sc.choice.orig_type is TRISTATE and \
|
||||
sc.orig_type is not TRISTATE and sc.choice.tri_value != 2:
|
||||
# Non-tristate choice symbols are only visible in y mode
|
||||
return 0
|
||||
|
||||
if sc.orig_type == TRISTATE and vis == 1 and sc.choice.tri_value == 2:
|
||||
if sc.orig_type is TRISTATE and vis == 1 and sc.choice.tri_value == 2:
|
||||
# Choice symbols with m visibility are not visible in y mode
|
||||
return 0
|
||||
|
||||
# Promote m to y if we're dealing with a non-tristate (possibly due to
|
||||
# modules being disabled)
|
||||
if vis == 1 and sc.type != TRISTATE:
|
||||
if vis == 1 and sc.type is not TRISTATE:
|
||||
return 2
|
||||
|
||||
return vis
|
||||
|
@ -5241,7 +5259,7 @@ def _make_depend_on(sc, expr):
|
|||
_make_depend_on(sc, expr[1])
|
||||
|
||||
# NOTs only have a single operand
|
||||
if expr[0] != NOT:
|
||||
if expr[0] is not NOT:
|
||||
_make_depend_on(sc, expr[2])
|
||||
|
||||
elif not expr.is_constant:
|
||||
|
@ -5251,7 +5269,7 @@ def _make_depend_on(sc, expr):
|
|||
def _parenthesize(expr, type_, sc_expr_str_fn):
|
||||
# expr_str() helper. Adds parentheses around expressions of type 'type_'.
|
||||
|
||||
if isinstance(expr, tuple) and expr[0] == type_:
|
||||
if isinstance(expr, tuple) and expr[0] is type_:
|
||||
return "({})".format(expr_str(expr, sc_expr_str_fn))
|
||||
return expr_str(expr, sc_expr_str_fn)
|
||||
|
||||
|
@ -5382,11 +5400,11 @@ def _expr_depends_on(expr, sym):
|
|||
elif left is not sym:
|
||||
return False
|
||||
|
||||
return (expr[0] == EQUAL and right is sym.kconfig.m or \
|
||||
return (expr[0] is EQUAL and right is sym.kconfig.m or \
|
||||
right is sym.kconfig.y) or \
|
||||
(expr[0] == UNEQUAL and right is sym.kconfig.n)
|
||||
(expr[0] is UNEQUAL and right is sym.kconfig.n)
|
||||
|
||||
return expr[0] == AND and \
|
||||
return expr[0] is AND and \
|
||||
(_expr_depends_on(expr[1], sym) or
|
||||
_expr_depends_on(expr[2], sym))
|
||||
|
||||
|
@ -5461,15 +5479,15 @@ def _finalize_choice(node):
|
|||
|
||||
# If no type is specified for the choice, its type is that of
|
||||
# the first choice item with a specified type
|
||||
if choice.orig_type == UNKNOWN:
|
||||
if choice.orig_type is UNKNOWN:
|
||||
for item in choice.syms:
|
||||
if item.orig_type != UNKNOWN:
|
||||
if item.orig_type is not UNKNOWN:
|
||||
choice.orig_type = item.orig_type
|
||||
break
|
||||
|
||||
# Each choice item of UNKNOWN type gets the type of the choice
|
||||
for sym in choice.syms:
|
||||
if sym.orig_type == UNKNOWN:
|
||||
if sym.orig_type is UNKNOWN:
|
||||
sym.orig_type = choice.orig_type
|
||||
|
||||
def _check_dep_loop_sym(sym, ignore_choice):
|
||||
|
@ -5661,7 +5679,7 @@ def _check_sym_sanity(sym):
|
|||
.format(TYPE_TO_STR[sym.orig_type], _name_and_loc(sym),
|
||||
expr_str(default)))
|
||||
|
||||
if sym.orig_type == STRING:
|
||||
if sym.orig_type is STRING:
|
||||
if not default.is_constant and not default.nodes and \
|
||||
not default.name.isupper():
|
||||
# 'default foo' on a string symbol could be either a symbol
|
||||
|
@ -5717,7 +5735,7 @@ def _int_hex_ok(sym, type_):
|
|||
if not sym.nodes:
|
||||
return _is_base_n(sym.name, _TYPE_TO_BASE[type_])
|
||||
|
||||
return sym.orig_type == type_
|
||||
return sym.orig_type is type_
|
||||
|
||||
def _check_choice_sanity(choice):
|
||||
# Checks various choice properties that are handiest to check after
|
||||
|
@ -5880,6 +5898,21 @@ STR_TO_TRI = {
|
|||
# constants)
|
||||
#
|
||||
|
||||
# Note:
|
||||
#
|
||||
# The token and type constants below are safe to test with 'is', which is a bit
|
||||
# faster (~30% faster in a microbenchmark with Python 3 on my machine, and a
|
||||
# few % faster for total parsing time), even without assuming Python's small
|
||||
# integer optimization (which caches small integer objects). The constants end
|
||||
# up pointing to unique integer objects, and since we consistently refer to
|
||||
# them via the names below, we always get the same object.
|
||||
#
|
||||
# Client code would also need to use the names below, because the integer
|
||||
# values can change e.g. when tokens get added. Client code would usually test
|
||||
# with == too, which would be safe even in super obscure cases involving e.g.
|
||||
# pickling (where 'is' would be a bad idea anyway) and no small-integer
|
||||
# optimization.
|
||||
|
||||
# Are we running on Python 2?
|
||||
_IS_PY2 = sys.version_info[0] < 3
|
||||
|
||||
|
@ -6055,12 +6088,13 @@ def _re_search(regex):
|
|||
#
|
||||
# This regex will also fail to match for empty lines and comment lines.
|
||||
#
|
||||
# '$' is included to detect a variable assignment left-hand side with a $ in it
|
||||
# (which might be from a macro expansion).
|
||||
# '$' is included to detect preprocessor variable assignments with macro
|
||||
# expansions in the left-hand side.
|
||||
_command_match = _re_match(r"\s*([$A-Za-z0-9_-]+)\s*")
|
||||
|
||||
# An identifier/keyword after the first token. Also eats trailing whitespace.
|
||||
_id_keyword_match = _re_match(r"([A-Za-z0-9_/.-]+)\s*")
|
||||
# '$' is included to detect identifiers containing macro expansions.
|
||||
_id_keyword_match = _re_match(r"([$A-Za-z0-9_/.-]+)\s*")
|
||||
|
||||
# A fragment in the left-hand side of a preprocessor variable assignment. These
|
||||
# are the portions between macro expansions ($(foo)). Macros are supported in
|
||||
|
@ -6077,6 +6111,10 @@ _macro_special_search = _re_search(r"\)|,|\$\(")
|
|||
# Special characters/strings while expanding a string (quotes, '\', and '$(')
|
||||
_string_special_search = _re_search(r'"|\'|\\|\$\(')
|
||||
|
||||
# Special characters/strings while expanding a symbol name. Also includes
|
||||
# end-of-line, in case the macro is the last thing on the line.
|
||||
_name_special_search = _re_search(r'[^$A-Za-z0-9_/.-]|\$\(|$')
|
||||
|
||||
# A valid right-hand side for an assignment to a string symbol in a .config
|
||||
# file, including escaped characters. Extracts the contents.
|
||||
_conf_string_match = _re_match(r'"((?:[^\\"]|\\.)*)"')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue