1f219e013SMasahiro Yamada# 2*9170818aSMasahiro Yamada# SPDX-License-Identifier: ISC 3f219e013SMasahiro Yamada# 4f219e013SMasahiro Yamada# Author: Ulf Magnusson 5f219e013SMasahiro Yamada# https://github.com/ulfalizer/Kconfiglib 6f219e013SMasahiro Yamada 7f219e013SMasahiro Yamada# This is Kconfiglib, a Python library for scripting, debugging, and extracting 8f219e013SMasahiro Yamada# information from Kconfig-based configuration systems. To view the 9f219e013SMasahiro Yamada# documentation, run 10f219e013SMasahiro Yamada# 11f219e013SMasahiro Yamada# $ pydoc kconfiglib 12f219e013SMasahiro Yamada# 13f219e013SMasahiro Yamada# or, if you prefer HTML, 14f219e013SMasahiro Yamada# 15f219e013SMasahiro Yamada# $ pydoc -w kconfiglib 16f219e013SMasahiro Yamada# 17f219e013SMasahiro Yamada# The examples/ subdirectory contains examples, to be run with e.g. 18f219e013SMasahiro Yamada# 19f219e013SMasahiro Yamada# $ make scriptconfig SCRIPT=Kconfiglib/examples/print_tree.py 20f219e013SMasahiro Yamada# 21f219e013SMasahiro Yamada# Look in testsuite.py for the test suite. 22f219e013SMasahiro Yamada 23f219e013SMasahiro Yamada""" 24f219e013SMasahiro YamadaKconfiglib is a Python library for scripting and extracting information from 25f219e013SMasahiro YamadaKconfig-based configuration systems. Features include the following: 26f219e013SMasahiro Yamada 27f219e013SMasahiro Yamada - Symbol values and properties can be looked up and values assigned 28f219e013SMasahiro Yamada programmatically. 29f219e013SMasahiro Yamada - .config files can be read and written. 30f219e013SMasahiro Yamada - Expressions can be evaluated in the context of a Kconfig configuration. 31f219e013SMasahiro Yamada - Relations between symbols can be quickly determined, such as finding all 32f219e013SMasahiro Yamada symbols that reference a particular symbol. 33f219e013SMasahiro Yamada - Highly compatible with the scripts/kconfig/*conf utilities. The test suite 34f219e013SMasahiro Yamada automatically compares outputs between Kconfiglib and the C implementation 35f219e013SMasahiro Yamada for a large number of cases. 36f219e013SMasahiro Yamada 37f219e013SMasahiro YamadaFor the Linux kernel, scripts are run using 38f219e013SMasahiro Yamada 39f219e013SMasahiro Yamada $ make scriptconfig SCRIPT=<path to script> [SCRIPT_ARG=<arg>] 40f219e013SMasahiro Yamada 41f219e013SMasahiro YamadaRunning scripts via the 'scriptconfig' target ensures that required environment 42f219e013SMasahiro Yamadavariables (SRCARCH, ARCH, srctree, KERNELVERSION, etc.) are set up correctly. 43f219e013SMasahiro YamadaAlternative architectures can be specified like for other 'make *config' 44f219e013SMasahiro Yamadatargets: 45f219e013SMasahiro Yamada 46f219e013SMasahiro Yamada $ make scriptconfig ARCH=mips SCRIPT=<path to script> [SCRIPT_ARG=<arg>] 47f219e013SMasahiro Yamada 48f219e013SMasahiro YamadaThe script will receive the name of the Kconfig file to load in sys.argv[1]. 49f219e013SMasahiro Yamada(As of Linux 3.7.0-rc8 this is always "Kconfig" from the kernel top-level 50f219e013SMasahiro Yamadadirectory.) If an argument is provided with SCRIPT_ARG, it will appear in 51f219e013SMasahiro Yamadasys.argv[2]. 52f219e013SMasahiro Yamada 53f219e013SMasahiro YamadaTo get an interactive Python prompt with Kconfiglib preloaded and a Config 54f219e013SMasahiro Yamadaobject 'c' created, use 55f219e013SMasahiro Yamada 56f219e013SMasahiro Yamada $ make iscriptconfig [ARCH=<architecture>] 57f219e013SMasahiro Yamada 58f219e013SMasahiro YamadaKconfiglib requires Python 2. For (i)scriptconfig the command to run the Python 59f219e013SMasahiro Yamadainterpreter can be passed in the environment variable PYTHONCMD (defaults to 60f219e013SMasahiro Yamada'python'; PyPy works too and is a bit faster). 61f219e013SMasahiro Yamada 62f219e013SMasahiro YamadaLook in the examples/ subdirectory for examples, which can be run with e.g. 63f219e013SMasahiro Yamada 64f219e013SMasahiro Yamada $ make scriptconfig SCRIPT=Kconfiglib/examples/print_tree.py 65f219e013SMasahiro Yamada 66f219e013SMasahiro Yamadaor 67f219e013SMasahiro Yamada 68f219e013SMasahiro Yamada $ make scriptconfig SCRIPT=Kconfiglib/examples/help_grep.py SCRIPT_ARG="kernel" 69f219e013SMasahiro Yamada 70f219e013SMasahiro YamadaLook in testsuite.py for the test suite. 71f219e013SMasahiro Yamada 72f219e013SMasahiro YamadaCredits: Written by Ulf "Ulfalizer" Magnusson 73f219e013SMasahiro Yamada 74f219e013SMasahiro YamadaSend bug reports, suggestions and other feedback to kconfiglib@gmail.com . 75f219e013SMasahiro YamadaDon't wrestle with internal APIs. Tell me what you need and I might add it in a 76f219e013SMasahiro Yamadasafe way as a client API instead.""" 77f219e013SMasahiro Yamada 78f219e013SMasahiro Yamada# If you have Psyco installed (32-bit installations, Python <= 2.6 only), 79f219e013SMasahiro Yamada# setting this to True (right here, not at runtime) might give a nice speedup. 80f219e013SMasahiro Yamada# (22% faster for parsing arch/x86/Kconfig and 58% faster for evaluating all 81f219e013SMasahiro Yamada# symbols in it without a .config on my Core Duo.) 82f219e013SMasahiro Yamadause_psyco = False 83f219e013SMasahiro Yamada 84f219e013SMasahiro Yamadaimport os 85f219e013SMasahiro Yamadaimport re 86f219e013SMasahiro Yamadaimport string 87f219e013SMasahiro Yamadaimport sys 88f219e013SMasahiro Yamada 89f219e013SMasahiro Yamadaclass Config(): 90f219e013SMasahiro Yamada 91f219e013SMasahiro Yamada """Represents a Kconfig configuration, e.g. for i386 or ARM. This is the 92f219e013SMasahiro Yamada set of symbols and other items appearing in the configuration together with 93f219e013SMasahiro Yamada their values. Creating any number of Config objects -- including for 94f219e013SMasahiro Yamada different architectures -- is safe; Kconfiglib has no global state.""" 95f219e013SMasahiro Yamada 96f219e013SMasahiro Yamada # 97f219e013SMasahiro Yamada # Public interface 98f219e013SMasahiro Yamada # 99f219e013SMasahiro Yamada 100f219e013SMasahiro Yamada def __init__(self, 101f219e013SMasahiro Yamada filename = "Kconfig", 102f219e013SMasahiro Yamada base_dir = "$srctree", 103f219e013SMasahiro Yamada print_warnings = True, 104f219e013SMasahiro Yamada print_undef_assign = False): 105f219e013SMasahiro Yamada """Creates a new Config object, representing a Kconfig configuration. 106f219e013SMasahiro Yamada Raises Kconfig_Syntax_Error on syntax errors. 107f219e013SMasahiro Yamada 108f219e013SMasahiro Yamada filename (default: "Kconfig") -- The base Kconfig file of the 109f219e013SMasahiro Yamada configuration. For the Linux kernel, this should usually be be 110f219e013SMasahiro Yamada "Kconfig" from the top-level directory, as environment 111f219e013SMasahiro Yamada variables will make sure the right Kconfig is included from 112f219e013SMasahiro Yamada there (usually arch/<architecture>/Kconfig). If you are using 113f219e013SMasahiro Yamada kconfiglib via 'make scriptconfig' the filename of the 114f219e013SMasahiro Yamada correct Kconfig will be in sys.argv[1]. 115f219e013SMasahiro Yamada 116f219e013SMasahiro Yamada base_dir (default: "$srctree") -- The base directory relative to which 117f219e013SMasahiro Yamada 'source' statements within Kconfig files will work. For the 118f219e013SMasahiro Yamada Linux kernel this should be the top-level directory of the 119f219e013SMasahiro Yamada kernel tree. $-references to environment variables will be 120f219e013SMasahiro Yamada expanded. 121f219e013SMasahiro Yamada 122f219e013SMasahiro Yamada The environment variable 'srctree' is set by the Linux makefiles 123f219e013SMasahiro Yamada to the top-level kernel directory. A default of "." would not 124f219e013SMasahiro Yamada work if an alternative build directory is used. 125f219e013SMasahiro Yamada 126f219e013SMasahiro Yamada print_warnings (default: True) -- Set to True if warnings related to 127f219e013SMasahiro Yamada this configuration should be printed to stderr. This can 128f219e013SMasahiro Yamada be changed later with Config.set_print_warnings(). It is 129f219e013SMasahiro Yamada provided as a constructor argument since warnings might 130f219e013SMasahiro Yamada be generated during parsing. 131f219e013SMasahiro Yamada 132f219e013SMasahiro Yamada print_undef_assign (default: False) -- Set to True if informational 133f219e013SMasahiro Yamada messages related to assignments to undefined symbols 134f219e013SMasahiro Yamada should be printed to stderr for this configuration. 135f219e013SMasahiro Yamada Can be changed later with 136f219e013SMasahiro Yamada Config.set_print_undef_assign().""" 137f219e013SMasahiro Yamada 138f219e013SMasahiro Yamada # The set of all symbols, indexed by name (a string) 139f219e013SMasahiro Yamada self.syms = {} 140f219e013SMasahiro Yamada 141f219e013SMasahiro Yamada # The set of all defined symbols in the configuration in the order they 142f219e013SMasahiro Yamada # appear in the Kconfig files. This excludes the special symbols n, m, 143f219e013SMasahiro Yamada # and y as well as symbols that are referenced but never defined. 144f219e013SMasahiro Yamada self.kconfig_syms = [] 145f219e013SMasahiro Yamada 146f219e013SMasahiro Yamada # The set of all named choices (yes, choices can have names), indexed 147f219e013SMasahiro Yamada # by name (a string) 148f219e013SMasahiro Yamada self.named_choices = {} 149f219e013SMasahiro Yamada 150f219e013SMasahiro Yamada def register_special_symbol(type, name, value): 151f219e013SMasahiro Yamada sym = Symbol() 152f219e013SMasahiro Yamada sym.is_special_ = True 153f219e013SMasahiro Yamada sym.is_defined_ = True 154f219e013SMasahiro Yamada sym.config = self 155f219e013SMasahiro Yamada sym.name = name 156f219e013SMasahiro Yamada sym.type = type 157f219e013SMasahiro Yamada sym.cached_value = value 158f219e013SMasahiro Yamada self.syms[name] = sym 159f219e013SMasahiro Yamada return sym 160f219e013SMasahiro Yamada 161f219e013SMasahiro Yamada # The special symbols n, m and y, used as shorthand for "n", "m" and 162f219e013SMasahiro Yamada # "y" 163f219e013SMasahiro Yamada self.n = register_special_symbol(TRISTATE, "n", "n") 164f219e013SMasahiro Yamada self.m = register_special_symbol(TRISTATE, "m", "m") 165f219e013SMasahiro Yamada self.y = register_special_symbol(TRISTATE, "y", "y") 166f219e013SMasahiro Yamada 167f219e013SMasahiro Yamada # DEFCONFIG_LIST uses this 168f219e013SMasahiro Yamada register_special_symbol(STRING, "UNAME_RELEASE", os.uname()[2]) 169f219e013SMasahiro Yamada 170f219e013SMasahiro Yamada # The symbol with "option defconfig_list" set, containing a list of 171f219e013SMasahiro Yamada # default .config files 172f219e013SMasahiro Yamada self.defconfig_sym = None 173f219e013SMasahiro Yamada 174f219e013SMasahiro Yamada # See Symbol.get_(src)arch() 175f219e013SMasahiro Yamada self.arch = os.environ.get("ARCH") 176f219e013SMasahiro Yamada self.srcarch = os.environ.get("SRCARCH") 177f219e013SMasahiro Yamada 178f219e013SMasahiro Yamada # See Config.__init__(). We need this for get_defconfig_filename(). 179f219e013SMasahiro Yamada self.srctree = os.environ.get("srctree") 180f219e013SMasahiro Yamada if self.srctree is None: 181f219e013SMasahiro Yamada self.srctree = "." 182f219e013SMasahiro Yamada 183f219e013SMasahiro Yamada self.filename = filename 184f219e013SMasahiro Yamada self.base_dir = _strip_trailing_slash(os.path.expandvars(base_dir)) 185f219e013SMasahiro Yamada 186f219e013SMasahiro Yamada # The 'mainmenu' text 187f219e013SMasahiro Yamada self.mainmenu_text = None 188f219e013SMasahiro Yamada 189f219e013SMasahiro Yamada # The filename of the most recently loaded .config file 190f219e013SMasahiro Yamada self.config_filename = None 191f219e013SMasahiro Yamada 192f219e013SMasahiro Yamada # The textual header of the most recently loaded .config, uncommented 193f219e013SMasahiro Yamada self.config_header = None 194f219e013SMasahiro Yamada 195f219e013SMasahiro Yamada self.print_warnings = print_warnings 196f219e013SMasahiro Yamada self.print_undef_assign = print_undef_assign 197f219e013SMasahiro Yamada 198f219e013SMasahiro Yamada # Lists containing all choices, menus and comments in the configuration 199f219e013SMasahiro Yamada 200f219e013SMasahiro Yamada self.choices = [] 201f219e013SMasahiro Yamada self.menus = [] 202f219e013SMasahiro Yamada self.comments = [] 203f219e013SMasahiro Yamada 204f219e013SMasahiro Yamada # For parsing routines that stop when finding a line belonging to a 205f219e013SMasahiro Yamada # different construct, these holds that line and the tokenized version 206f219e013SMasahiro Yamada # of that line. The purpose is to avoid having to re-tokenize the line, 207f219e013SMasahiro Yamada # which is inefficient and causes problems when recording references to 208f219e013SMasahiro Yamada # symbols. 209f219e013SMasahiro Yamada self.end_line = None 210f219e013SMasahiro Yamada self.end_line_tokens = None 211f219e013SMasahiro Yamada 212f219e013SMasahiro Yamada # See the comment in _parse_expr(). 213f219e013SMasahiro Yamada self.parse_expr_cur_sym_or_choice = None 214f219e013SMasahiro Yamada self.parse_expr_line = None 215f219e013SMasahiro Yamada self.parse_expr_filename = None 216f219e013SMasahiro Yamada self.parse_expr_linenr = None 217f219e013SMasahiro Yamada self.parse_expr_transform_m = None 218f219e013SMasahiro Yamada 219f219e013SMasahiro Yamada # Parse the Kconfig files 220f219e013SMasahiro Yamada self.top_block = self._parse_file(filename, None, None, None) 221f219e013SMasahiro Yamada 222f219e013SMasahiro Yamada # Build Symbol.dep for all symbols 223f219e013SMasahiro Yamada self._build_dep() 224f219e013SMasahiro Yamada 225f219e013SMasahiro Yamada def load_config(self, filename, replace = True): 226f219e013SMasahiro Yamada """Loads symbol values from a file in the familiar .config format. 227f219e013SMasahiro Yamada Equivalent to calling Symbol.set_user_value() to set each of the 228f219e013SMasahiro Yamada values. 229f219e013SMasahiro Yamada 230f219e013SMasahiro Yamada filename -- The .config file to load. $-references to environment 231f219e013SMasahiro Yamada variables will be expanded. For scripts to work even 232f219e013SMasahiro Yamada when an alternative build directory is used with the 233f219e013SMasahiro Yamada Linux kernel, you need to refer to the top-level kernel 234f219e013SMasahiro Yamada directory with "$srctree". 235f219e013SMasahiro Yamada 236f219e013SMasahiro Yamada replace (default: True) -- True if the configuration should replace 237f219e013SMasahiro Yamada the old configuration; False if it should add to it.""" 238f219e013SMasahiro Yamada 239f219e013SMasahiro Yamada def warn_override(filename, linenr, name, old_user_val, new_user_val): 240f219e013SMasahiro Yamada self._warn("overriding the value of {0}. " 241f219e013SMasahiro Yamada 'Old value: "{1}", new value: "{2}".' 242f219e013SMasahiro Yamada .format(name, old_user_val, new_user_val), 243f219e013SMasahiro Yamada filename, 244f219e013SMasahiro Yamada linenr) 245f219e013SMasahiro Yamada 246f219e013SMasahiro Yamada filename = os.path.expandvars(filename) 247f219e013SMasahiro Yamada 248f219e013SMasahiro Yamada # Put this first so that a missing file doesn't screw up our state 249f219e013SMasahiro Yamada line_feeder = _FileFeed(_get_lines(filename), filename) 250f219e013SMasahiro Yamada 251f219e013SMasahiro Yamada self.config_filename = filename 252f219e013SMasahiro Yamada 253f219e013SMasahiro Yamada # Invalidate everything. This is usually faster than finding the 254f219e013SMasahiro Yamada # minimal set of symbols that needs to be invalidated, as nearly all 255f219e013SMasahiro Yamada # symbols will tend to be affected anyway. 256f219e013SMasahiro Yamada if replace: 257f219e013SMasahiro Yamada self.unset_user_values() 258f219e013SMasahiro Yamada else: 259f219e013SMasahiro Yamada self._invalidate_all() 260f219e013SMasahiro Yamada 261f219e013SMasahiro Yamada # Read header 262f219e013SMasahiro Yamada 263f219e013SMasahiro Yamada self.config_header = None 264f219e013SMasahiro Yamada 265f219e013SMasahiro Yamada def is_header_line(line): 266f219e013SMasahiro Yamada return line.startswith("#") and \ 267f219e013SMasahiro Yamada not unset_re.match(line) 268f219e013SMasahiro Yamada 269f219e013SMasahiro Yamada first_line = line_feeder.get_next() 270f219e013SMasahiro Yamada 271f219e013SMasahiro Yamada if first_line is None: 272f219e013SMasahiro Yamada return 273f219e013SMasahiro Yamada 274f219e013SMasahiro Yamada if not is_header_line(first_line): 275f219e013SMasahiro Yamada line_feeder.go_back() 276f219e013SMasahiro Yamada else: 277f219e013SMasahiro Yamada self.config_header = first_line[1:] 278f219e013SMasahiro Yamada 279f219e013SMasahiro Yamada # Read remaining header lines 280f219e013SMasahiro Yamada while 1: 281f219e013SMasahiro Yamada line = line_feeder.get_next() 282f219e013SMasahiro Yamada 283f219e013SMasahiro Yamada if line is None: 284f219e013SMasahiro Yamada break 285f219e013SMasahiro Yamada 286f219e013SMasahiro Yamada if not is_header_line(line): 287f219e013SMasahiro Yamada line_feeder.go_back() 288f219e013SMasahiro Yamada break 289f219e013SMasahiro Yamada 290f219e013SMasahiro Yamada self.config_header += line[1:] 291f219e013SMasahiro Yamada 292f219e013SMasahiro Yamada # Remove trailing newline 293f219e013SMasahiro Yamada if self.config_header.endswith("\n"): 294f219e013SMasahiro Yamada self.config_header = self.config_header[:-1] 295f219e013SMasahiro Yamada 296f219e013SMasahiro Yamada # Read assignments 297f219e013SMasahiro Yamada 298f219e013SMasahiro Yamada filename = line_feeder.get_filename() 299f219e013SMasahiro Yamada 300f219e013SMasahiro Yamada while 1: 301f219e013SMasahiro Yamada line = line_feeder.get_next() 302f219e013SMasahiro Yamada if line is None: 303f219e013SMasahiro Yamada return 304f219e013SMasahiro Yamada 305f219e013SMasahiro Yamada linenr = line_feeder.get_linenr() 306f219e013SMasahiro Yamada 307f219e013SMasahiro Yamada line = line.strip() 308f219e013SMasahiro Yamada 309f219e013SMasahiro Yamada set_re_match = set_re.match(line) 310f219e013SMasahiro Yamada if set_re_match: 311f219e013SMasahiro Yamada name, val = set_re_match.groups() 312f219e013SMasahiro Yamada # The unescaping producedure below should be safe since " can 313f219e013SMasahiro Yamada # only appear as \" inside the string 314f219e013SMasahiro Yamada val = _strip_quotes(val, line, filename, linenr)\ 315f219e013SMasahiro Yamada .replace('\\"', '"').replace("\\\\", "\\") 316f219e013SMasahiro Yamada if name in self.syms: 317f219e013SMasahiro Yamada sym = self.syms[name] 318f219e013SMasahiro Yamada 319f219e013SMasahiro Yamada old_user_val = sym.user_val 320f219e013SMasahiro Yamada if old_user_val is not None: 321f219e013SMasahiro Yamada warn_override(filename, linenr, name, old_user_val, val) 322f219e013SMasahiro Yamada 323f219e013SMasahiro Yamada if sym.is_choice_symbol_: 324f219e013SMasahiro Yamada user_mode = sym.parent.user_mode 325f219e013SMasahiro Yamada if user_mode is not None and user_mode != val: 326f219e013SMasahiro Yamada self._warn("assignment to {0} changes mode of containing " 327f219e013SMasahiro Yamada 'choice from "{1}" to "{2}".' 328f219e013SMasahiro Yamada .format(name, val, user_mode), 329f219e013SMasahiro Yamada filename, 330f219e013SMasahiro Yamada linenr) 331f219e013SMasahiro Yamada 332f219e013SMasahiro Yamada sym._set_user_value_no_invalidate(val, True) 333f219e013SMasahiro Yamada 334f219e013SMasahiro Yamada else: 335f219e013SMasahiro Yamada self._undef_assign('attempt to assign the value "{0}" to the ' 336f219e013SMasahiro Yamada "undefined symbol {1}." 337f219e013SMasahiro Yamada .format(val, name), 338f219e013SMasahiro Yamada filename, 339f219e013SMasahiro Yamada linenr) 340f219e013SMasahiro Yamada 341f219e013SMasahiro Yamada else: 342f219e013SMasahiro Yamada unset_re_match = unset_re.match(line) 343f219e013SMasahiro Yamada if unset_re_match: 344f219e013SMasahiro Yamada name = unset_re_match.group(1) 345f219e013SMasahiro Yamada if name in self.syms: 346f219e013SMasahiro Yamada sym = self.syms[name] 347f219e013SMasahiro Yamada 348f219e013SMasahiro Yamada old_user_val = sym.user_val 349f219e013SMasahiro Yamada if old_user_val is not None: 350f219e013SMasahiro Yamada warn_override(filename, linenr, name, old_user_val, "n") 351f219e013SMasahiro Yamada 352f219e013SMasahiro Yamada sym._set_user_value_no_invalidate("n", True) 353f219e013SMasahiro Yamada 354f219e013SMasahiro Yamada def write_config(self, filename, header = None): 355f219e013SMasahiro Yamada """Writes out symbol values in the familiar .config format. 356f219e013SMasahiro Yamada 357f219e013SMasahiro Yamada filename -- The filename under which to save the configuration. 358f219e013SMasahiro Yamada 359f219e013SMasahiro Yamada header (default: None) -- A textual header that will appear at the 360f219e013SMasahiro Yamada beginning of the file, with each line commented out 361f219e013SMasahiro Yamada automatically. None means no header.""" 362f219e013SMasahiro Yamada 363f219e013SMasahiro Yamada # already_written is set when _make_conf() is called on a symbol, so 364f219e013SMasahiro Yamada # that symbols defined in multiple locations only get one entry in the 365f219e013SMasahiro Yamada # .config. We need to reset it prior to writing out a new .config. 366f219e013SMasahiro Yamada for sym in self.syms.itervalues(): 367f219e013SMasahiro Yamada sym.already_written = False 368f219e013SMasahiro Yamada 369f219e013SMasahiro Yamada with open(filename, "w") as f: 370f219e013SMasahiro Yamada # Write header 371f219e013SMasahiro Yamada if header is not None: 372f219e013SMasahiro Yamada f.write(_comment(header)) 373f219e013SMasahiro Yamada f.write("\n") 374f219e013SMasahiro Yamada 375f219e013SMasahiro Yamada # Write configuration. 376f219e013SMasahiro Yamada # (You'd think passing a list around to all the nodes and appending 377f219e013SMasahiro Yamada # to it to avoid copying would be faster, but it's actually a lot 378f219e013SMasahiro Yamada # slower with PyPy, and about as fast with Python. Passing the file 379f219e013SMasahiro Yamada # around is slower too.) 380f219e013SMasahiro Yamada f.write("\n".join(self.top_block._make_conf())) 381f219e013SMasahiro Yamada f.write("\n") 382f219e013SMasahiro Yamada 383f219e013SMasahiro Yamada def get_kconfig_filename(self): 384f219e013SMasahiro Yamada """Returns the name of the (base) kconfig file this configuration was 385f219e013SMasahiro Yamada loaded from.""" 386f219e013SMasahiro Yamada return self.filename 387f219e013SMasahiro Yamada 388f219e013SMasahiro Yamada def get_arch(self): 389f219e013SMasahiro Yamada """Returns the value the environment variable ARCH had at the time the 390f219e013SMasahiro Yamada Config instance was created, or None if ARCH was not set. For the 391f219e013SMasahiro Yamada kernel, this corresponds to the architecture being built for, with 392f219e013SMasahiro Yamada values such as "i386" or "mips".""" 393f219e013SMasahiro Yamada return self.arch 394f219e013SMasahiro Yamada 395f219e013SMasahiro Yamada def get_srcarch(self): 396f219e013SMasahiro Yamada """Returns the value the environment variable SRCARCH had at the time 397f219e013SMasahiro Yamada the Config instance was created, or None if SRCARCH was not set. For 398f219e013SMasahiro Yamada the kernel, this corresponds to the arch/ subdirectory containing 399f219e013SMasahiro Yamada architecture-specific source code.""" 400f219e013SMasahiro Yamada return self.srcarch 401f219e013SMasahiro Yamada 402f219e013SMasahiro Yamada def get_srctree(self): 403f219e013SMasahiro Yamada """Returns the value the environment variable srctree had at the time 404f219e013SMasahiro Yamada the Config instance was created, or None if srctree was not defined. 405f219e013SMasahiro Yamada This variable points to the source directory and is used when building 406f219e013SMasahiro Yamada in a separate directory.""" 407f219e013SMasahiro Yamada return self.srctree 408f219e013SMasahiro Yamada 409f219e013SMasahiro Yamada def get_config_filename(self): 410f219e013SMasahiro Yamada """Returns the name of the most recently loaded configuration file, or 411f219e013SMasahiro Yamada None if no configuration has been loaded.""" 412f219e013SMasahiro Yamada return self.config_filename 413f219e013SMasahiro Yamada 414f219e013SMasahiro Yamada def get_mainmenu_text(self): 415f219e013SMasahiro Yamada """Returns the text of the 'mainmenu' statement (with $-references to 416f219e013SMasahiro Yamada symbols replaced by symbol values), or None if the configuration has no 417f219e013SMasahiro Yamada 'mainmenu' statement.""" 418f219e013SMasahiro Yamada return None if self.mainmenu_text is None else \ 419f219e013SMasahiro Yamada self._expand_sym_refs(self.mainmenu_text) 420f219e013SMasahiro Yamada 421f219e013SMasahiro Yamada def get_defconfig_filename(self): 422f219e013SMasahiro Yamada """Returns the name of the defconfig file, which is the first existing 423f219e013SMasahiro Yamada file in the list given in a symbol having 'option defconfig_list' set. 424f219e013SMasahiro Yamada $-references to symbols will be expanded ("$FOO bar" -> "foo bar" if 425f219e013SMasahiro Yamada FOO has the value "foo"). Returns None in case of no defconfig file. 426f219e013SMasahiro Yamada Setting 'option defconfig_list' on multiple symbols currently results 427f219e013SMasahiro Yamada in undefined behavior. 428f219e013SMasahiro Yamada 429f219e013SMasahiro Yamada If the environment variable 'srctree' was set when the Config was 430f219e013SMasahiro Yamada created, get_defconfig_filename() will first look relative to that 431f219e013SMasahiro Yamada directory before looking in the current directory; see 432f219e013SMasahiro Yamada Config.__init__().""" 433f219e013SMasahiro Yamada 434f219e013SMasahiro Yamada if self.defconfig_sym is None: 435f219e013SMasahiro Yamada return None 436f219e013SMasahiro Yamada 437f219e013SMasahiro Yamada for (filename, cond_expr) in self.defconfig_sym.def_exprs: 438f219e013SMasahiro Yamada if self._eval_expr(cond_expr) == "y": 439f219e013SMasahiro Yamada filename = self._expand_sym_refs(filename) 440f219e013SMasahiro Yamada 441f219e013SMasahiro Yamada # We first look in $srctree. os.path.join() won't work here as 442f219e013SMasahiro Yamada # an absolute path in filename would override $srctree. 443f219e013SMasahiro Yamada srctree_filename = os.path.normpath(self.srctree + "/" + filename) 444f219e013SMasahiro Yamada if os.path.exists(srctree_filename): 445f219e013SMasahiro Yamada return srctree_filename 446f219e013SMasahiro Yamada 447f219e013SMasahiro Yamada if os.path.exists(filename): 448f219e013SMasahiro Yamada return filename 449f219e013SMasahiro Yamada 450f219e013SMasahiro Yamada return None 451f219e013SMasahiro Yamada 452f219e013SMasahiro Yamada def get_symbol(self, name): 453f219e013SMasahiro Yamada """Returns the symbol with name 'name', or None if no such symbol 454f219e013SMasahiro Yamada appears in the configuration. An alternative shorthand is conf[name], 455f219e013SMasahiro Yamada where conf is a Config instance, though that will instead raise 456f219e013SMasahiro Yamada KeyError if the symbol does not exist.""" 457f219e013SMasahiro Yamada return self.syms.get(name) 458f219e013SMasahiro Yamada 459f219e013SMasahiro Yamada def get_top_level_items(self): 460f219e013SMasahiro Yamada """Returns a list containing the items (symbols, menus, choice 461f219e013SMasahiro Yamada statements and comments) at the top level of the configuration -- that 462f219e013SMasahiro Yamada is, all items that do not appear within a menu or choice. The items 463f219e013SMasahiro Yamada appear in the same order as within the configuration.""" 464f219e013SMasahiro Yamada return self.top_block.get_items() 465f219e013SMasahiro Yamada 466f219e013SMasahiro Yamada def get_symbols(self, all_symbols = True): 467f219e013SMasahiro Yamada """Returns a list of symbols from the configuration. An alternative for 468f219e013SMasahiro Yamada iterating over all defined symbols (in the order of definition) is 469f219e013SMasahiro Yamada 470f219e013SMasahiro Yamada for sym in config: 471f219e013SMasahiro Yamada ... 472f219e013SMasahiro Yamada 473f219e013SMasahiro Yamada which relies on Config implementing __iter__() and is equivalent to 474f219e013SMasahiro Yamada 475f219e013SMasahiro Yamada for sym in config.get_symbols(False): 476f219e013SMasahiro Yamada ... 477f219e013SMasahiro Yamada 478f219e013SMasahiro Yamada all_symbols (default: True) -- If True, all symbols - including special 479f219e013SMasahiro Yamada and undefined symbols - will be included in the result, in 480f219e013SMasahiro Yamada an undefined order. If False, only symbols actually defined 481f219e013SMasahiro Yamada and not merely referred to in the configuration will be 482f219e013SMasahiro Yamada included in the result, and will appear in the order that 483f219e013SMasahiro Yamada they are defined within the Kconfig configuration files.""" 484f219e013SMasahiro Yamada return self.syms.values() if all_symbols else self.kconfig_syms 485f219e013SMasahiro Yamada 486f219e013SMasahiro Yamada def get_choices(self): 487f219e013SMasahiro Yamada """Returns a list containing all choice statements in the 488f219e013SMasahiro Yamada configuration, in the order they appear in the Kconfig files.""" 489f219e013SMasahiro Yamada return self.choices 490f219e013SMasahiro Yamada 491f219e013SMasahiro Yamada def get_menus(self): 492f219e013SMasahiro Yamada """Returns a list containing all menus in the configuration, in the 493f219e013SMasahiro Yamada order they appear in the Kconfig files.""" 494f219e013SMasahiro Yamada return self.menus 495f219e013SMasahiro Yamada 496f219e013SMasahiro Yamada def get_comments(self): 497f219e013SMasahiro Yamada """Returns a list containing all comments in the configuration, in the 498f219e013SMasahiro Yamada order they appear in the Kconfig files.""" 499f219e013SMasahiro Yamada return self.comments 500f219e013SMasahiro Yamada 501f219e013SMasahiro Yamada def eval(self, s): 502f219e013SMasahiro Yamada """Returns the value of the expression 's' -- where 's' is represented 503f219e013SMasahiro Yamada as a string -- in the context of the configuration. Raises 504f219e013SMasahiro Yamada Kconfig_Syntax_Error if syntax errors are detected in 's'. 505f219e013SMasahiro Yamada 506f219e013SMasahiro Yamada For example, if FOO and BAR are tristate symbols at least one of which 507f219e013SMasahiro Yamada has the value "y", then config.eval("y && (FOO || BAR)") => "y" 508f219e013SMasahiro Yamada 509f219e013SMasahiro Yamada This functions always yields a tristate value. To get the value of 510f219e013SMasahiro Yamada non-bool, non-tristate symbols, use Symbol.get_value(). 511f219e013SMasahiro Yamada 512f219e013SMasahiro Yamada The result of this function is consistent with how evaluation works for 513f219e013SMasahiro Yamada conditional expressions in the configuration as well as in the C 514f219e013SMasahiro Yamada implementation. "m" and m are rewritten as '"m" && MODULES' and 'm && 515f219e013SMasahiro Yamada MODULES', respectively, and a result of "m" will get promoted to "y" if 516f219e013SMasahiro Yamada we're running without modules.""" 517f219e013SMasahiro Yamada return self._eval_expr(self._parse_expr(self._tokenize(s, True), # Feed 518f219e013SMasahiro Yamada None, # Current symbol or choice 519f219e013SMasahiro Yamada s)) # line 520f219e013SMasahiro Yamada 521f219e013SMasahiro Yamada def get_config_header(self): 522f219e013SMasahiro Yamada """Returns the (uncommented) textual header of the .config file most 523f219e013SMasahiro Yamada recently loaded with load_config(). Returns None if no .config file has 524f219e013SMasahiro Yamada been loaded or if the most recently loaded .config file has no header. 525f219e013SMasahiro Yamada The header comprises all lines up to but not including the first line 526f219e013SMasahiro Yamada that either 527f219e013SMasahiro Yamada 528f219e013SMasahiro Yamada 1. Does not start with "#" 529f219e013SMasahiro Yamada 2. Has the form "# CONFIG_FOO is not set." 530f219e013SMasahiro Yamada """ 531f219e013SMasahiro Yamada return self.config_header 532f219e013SMasahiro Yamada 533f219e013SMasahiro Yamada def get_base_dir(self): 534f219e013SMasahiro Yamada """Returns the base directory relative to which 'source' statements 535f219e013SMasahiro Yamada will work, passed as an argument to Config.__init__().""" 536f219e013SMasahiro Yamada return self.base_dir 537f219e013SMasahiro Yamada 538f219e013SMasahiro Yamada def set_print_warnings(self, print_warnings): 539f219e013SMasahiro Yamada """Determines whether warnings related to this configuration (for 540f219e013SMasahiro Yamada things like attempting to assign illegal values to symbols with 541f219e013SMasahiro Yamada Symbol.set_user_value()) should be printed to stderr. 542f219e013SMasahiro Yamada 543f219e013SMasahiro Yamada print_warnings -- True if warnings should be 544f219e013SMasahiro Yamada printed, otherwise False.""" 545f219e013SMasahiro Yamada self.print_warnings = print_warnings 546f219e013SMasahiro Yamada 547f219e013SMasahiro Yamada def set_print_undef_assign(self, print_undef_assign): 548f219e013SMasahiro Yamada """Determines whether informational messages related to assignments to 549f219e013SMasahiro Yamada undefined symbols should be printed to stderr for this configuration. 550f219e013SMasahiro Yamada 551f219e013SMasahiro Yamada print_undef_assign -- If True, such messages will be printed.""" 552f219e013SMasahiro Yamada self.print_undef_assign = print_undef_assign 553f219e013SMasahiro Yamada 554f219e013SMasahiro Yamada def __getitem__(self, key): 555f219e013SMasahiro Yamada """Returns the symbol with name 'name'. Raises KeyError if the symbol 556f219e013SMasahiro Yamada does not appear in the configuration.""" 557f219e013SMasahiro Yamada return self.syms[key] 558f219e013SMasahiro Yamada 559f219e013SMasahiro Yamada def __iter__(self): 560f219e013SMasahiro Yamada """Convenience function for iterating over the set of all defined 561f219e013SMasahiro Yamada symbols in the configuration, used like 562f219e013SMasahiro Yamada 563f219e013SMasahiro Yamada for sym in conf: 564f219e013SMasahiro Yamada ... 565f219e013SMasahiro Yamada 566f219e013SMasahiro Yamada The iteration happens in the order of definition within the Kconfig 567f219e013SMasahiro Yamada configuration files. Symbols only referred to but not defined will not 568f219e013SMasahiro Yamada be included, nor will the special symbols n, m, and y. If you want to 569f219e013SMasahiro Yamada include such symbols as well, see config.get_symbols().""" 570f219e013SMasahiro Yamada return iter(self.kconfig_syms) 571f219e013SMasahiro Yamada 572f219e013SMasahiro Yamada def unset_user_values(self): 573f219e013SMasahiro Yamada """Resets the values of all symbols, as if Config.load_config() or 574f219e013SMasahiro Yamada Symbol.set_user_value() had never been called.""" 575f219e013SMasahiro Yamada for sym in self.syms.itervalues(): 576f219e013SMasahiro Yamada sym._unset_user_value_no_recursive_invalidate() 577f219e013SMasahiro Yamada 578f219e013SMasahiro Yamada def __str__(self): 579f219e013SMasahiro Yamada """Returns a string containing various information about the Config.""" 580f219e013SMasahiro Yamada return _sep_lines("Configuration", 581f219e013SMasahiro Yamada "File : " + self.filename, 582f219e013SMasahiro Yamada "Base directory : " + self.base_dir, 583f219e013SMasahiro Yamada "Value of $ARCH at creation time : " + 584f219e013SMasahiro Yamada ("(not set)" if self.arch is None else self.arch), 585f219e013SMasahiro Yamada "Value of $SRCARCH at creation time : " + 586f219e013SMasahiro Yamada ("(not set)" if self.srcarch is None else self.srcarch), 587f219e013SMasahiro Yamada "Source tree (derived from $srctree;", 588f219e013SMasahiro Yamada "defaults to '.' if $srctree isn't set) : " + self.srctree, 589f219e013SMasahiro Yamada "Most recently loaded .config : " + 590f219e013SMasahiro Yamada ("(no .config loaded)" if self.config_filename is None else 591f219e013SMasahiro Yamada self.config_filename), 592f219e013SMasahiro Yamada "Print warnings : " + 593f219e013SMasahiro Yamada bool_str[self.print_warnings], 594f219e013SMasahiro Yamada "Print assignments to undefined symbols : " + 595f219e013SMasahiro Yamada bool_str[self.print_undef_assign]) 596f219e013SMasahiro Yamada 597f219e013SMasahiro Yamada 598f219e013SMasahiro Yamada # 599f219e013SMasahiro Yamada # Private methods 600f219e013SMasahiro Yamada # 601f219e013SMasahiro Yamada 602f219e013SMasahiro Yamada def _invalidate_all(self): 603f219e013SMasahiro Yamada for sym in self.syms.itervalues(): 604f219e013SMasahiro Yamada sym._invalidate() 605f219e013SMasahiro Yamada 606f219e013SMasahiro Yamada def _tokenize(self, 607f219e013SMasahiro Yamada s, 608f219e013SMasahiro Yamada for_eval = False, 609f219e013SMasahiro Yamada filename = None, 610f219e013SMasahiro Yamada linenr = None): 611f219e013SMasahiro Yamada """Returns a _Feed instance containing tokens derived from the string 612f219e013SMasahiro Yamada 's'. Registers any new symbols encountered (via _sym_lookup()). 613f219e013SMasahiro Yamada 614f219e013SMasahiro Yamada (I experimented with a pure regular expression implementation, but it 615f219e013SMasahiro Yamada came out slower, less readable, and wouldn't have been as flexible.) 616f219e013SMasahiro Yamada 617f219e013SMasahiro Yamada for_eval -- True when parsing an expression for a call to 618f219e013SMasahiro Yamada Config.eval(), in which case we should not treat the first 619f219e013SMasahiro Yamada token specially nor register new symbols.""" 620f219e013SMasahiro Yamada s = s.lstrip() 621f219e013SMasahiro Yamada if s == "" or s[0] == "#": 622f219e013SMasahiro Yamada return _Feed([]) 623f219e013SMasahiro Yamada 624f219e013SMasahiro Yamada if for_eval: 625f219e013SMasahiro Yamada i = 0 # The current index in the string being tokenized 626f219e013SMasahiro Yamada previous = None # The previous token seen 627f219e013SMasahiro Yamada tokens = [] 628f219e013SMasahiro Yamada else: 629f219e013SMasahiro Yamada # The initial word on a line is parsed specially. Let 630f219e013SMasahiro Yamada # command_chars = [A-Za-z0-9_]. Then 631f219e013SMasahiro Yamada # - leading non-command_chars characters on the line are ignored, and 632f219e013SMasahiro Yamada # - the first token consists the following one or more command_chars 633f219e013SMasahiro Yamada # characters. 634f219e013SMasahiro Yamada # This is why things like "----help--" are accepted. 635f219e013SMasahiro Yamada 636f219e013SMasahiro Yamada initial_token_match = initial_token_re.match(s) 637f219e013SMasahiro Yamada if initial_token_match is None: 638f219e013SMasahiro Yamada return _Feed([]) 639f219e013SMasahiro Yamada # The current index in the string being tokenized 640f219e013SMasahiro Yamada i = initial_token_match.end() 641f219e013SMasahiro Yamada 642f219e013SMasahiro Yamada keyword = keywords.get(initial_token_match.group(1)) 643f219e013SMasahiro Yamada if keyword is None: 644f219e013SMasahiro Yamada # We expect a keyword as the first token 645f219e013SMasahiro Yamada _tokenization_error(s, len(s), filename, linenr) 646f219e013SMasahiro Yamada if keyword == T_HELP: 647f219e013SMasahiro Yamada # Avoid junk after "help", e.g. "---", being registered as a 648f219e013SMasahiro Yamada # symbol 649f219e013SMasahiro Yamada return _Feed([T_HELP]) 650f219e013SMasahiro Yamada tokens = [keyword] 651f219e013SMasahiro Yamada previous = keyword 652f219e013SMasahiro Yamada 653f219e013SMasahiro Yamada # _tokenize() is a hotspot during parsing, and this speeds things up a 654f219e013SMasahiro Yamada # bit 655f219e013SMasahiro Yamada strlen = len(s) 656f219e013SMasahiro Yamada append = tokens.append 657f219e013SMasahiro Yamada 658f219e013SMasahiro Yamada # Main tokenization loop. (Handles tokens past the first one.) 659f219e013SMasahiro Yamada while i < strlen: 660f219e013SMasahiro Yamada # Test for an identifier/keyword preceded by whitespace first; this 661f219e013SMasahiro Yamada # is the most common case. 662f219e013SMasahiro Yamada id_keyword_match = id_keyword_re.match(s, i) 663f219e013SMasahiro Yamada if id_keyword_match: 664f219e013SMasahiro Yamada # We have an identifier or keyword. The above also stripped any 665f219e013SMasahiro Yamada # whitespace for us. 666f219e013SMasahiro Yamada name = id_keyword_match.group(1) 667f219e013SMasahiro Yamada # Jump past it 668f219e013SMasahiro Yamada i = id_keyword_match.end() 669f219e013SMasahiro Yamada 670f219e013SMasahiro Yamada # Keyword? 671f219e013SMasahiro Yamada keyword = keywords.get(name) 672f219e013SMasahiro Yamada if keyword is not None: 673f219e013SMasahiro Yamada append(keyword) 674f219e013SMasahiro Yamada # What would ordinarily be considered a name is treated as a 675f219e013SMasahiro Yamada # string after certain tokens. 676f219e013SMasahiro Yamada elif previous in string_lex: 677f219e013SMasahiro Yamada append(name) 678f219e013SMasahiro Yamada else: 679f219e013SMasahiro Yamada # We're dealing with a symbol. _sym_lookup() will take care 680f219e013SMasahiro Yamada # of allocating a new Symbol instance if it's the first 681f219e013SMasahiro Yamada # time we see it. 682f219e013SMasahiro Yamada sym = self._sym_lookup(name, not for_eval) 683f219e013SMasahiro Yamada 684f219e013SMasahiro Yamada if previous == T_CONFIG or previous == T_MENUCONFIG: 685f219e013SMasahiro Yamada # If the previous token is T_(MENU)CONFIG 686f219e013SMasahiro Yamada # ("(menu)config"), we're tokenizing the first line of 687f219e013SMasahiro Yamada # a symbol definition, and should remember this as a 688f219e013SMasahiro Yamada # location where the symbol is defined. 689f219e013SMasahiro Yamada sym.def_locations.append((filename, linenr)) 690f219e013SMasahiro Yamada else: 691f219e013SMasahiro Yamada # Otherwise, it's a reference to the symbol 692f219e013SMasahiro Yamada sym.ref_locations.append((filename, linenr)) 693f219e013SMasahiro Yamada 694f219e013SMasahiro Yamada append(sym) 695f219e013SMasahiro Yamada 696f219e013SMasahiro Yamada else: 697f219e013SMasahiro Yamada # This restrips whitespace that could have been stripped in the 698f219e013SMasahiro Yamada # regex above, but it's worth it since identifiers/keywords are 699f219e013SMasahiro Yamada # more common 700f219e013SMasahiro Yamada s = s[i:].lstrip() 701f219e013SMasahiro Yamada if s == "": 702f219e013SMasahiro Yamada break 703f219e013SMasahiro Yamada strlen = len(s) 704f219e013SMasahiro Yamada i = 0 705f219e013SMasahiro Yamada c = s[0] 706f219e013SMasahiro Yamada 707f219e013SMasahiro Yamada # String literal (constant symbol) 708f219e013SMasahiro Yamada if c == '"' or c == "'": 709f219e013SMasahiro Yamada i += 1 710f219e013SMasahiro Yamada 711f219e013SMasahiro Yamada if "\\" in s: 712f219e013SMasahiro Yamada # Slow path: This could probably be sped up, but it's a 713f219e013SMasahiro Yamada # very unusual case anyway. 714f219e013SMasahiro Yamada quote = c 715f219e013SMasahiro Yamada value = "" 716f219e013SMasahiro Yamada while 1: 717f219e013SMasahiro Yamada if i >= strlen: 718f219e013SMasahiro Yamada _tokenization_error(s, strlen, filename, 719f219e013SMasahiro Yamada linenr) 720f219e013SMasahiro Yamada c = s[i] 721f219e013SMasahiro Yamada if c == quote: 722f219e013SMasahiro Yamada break 723f219e013SMasahiro Yamada if c == "\\": 724f219e013SMasahiro Yamada if i + 1 >= strlen: 725f219e013SMasahiro Yamada _tokenization_error(s, strlen, filename, 726f219e013SMasahiro Yamada linenr) 727f219e013SMasahiro Yamada value += s[i + 1] 728f219e013SMasahiro Yamada i += 2 729f219e013SMasahiro Yamada else: 730f219e013SMasahiro Yamada value += c 731f219e013SMasahiro Yamada i += 1 732f219e013SMasahiro Yamada i += 1 733f219e013SMasahiro Yamada append(value) 734f219e013SMasahiro Yamada else: 735f219e013SMasahiro Yamada # Fast path: If the string contains no backslashes (almost 736f219e013SMasahiro Yamada # always) we can simply look for the matching quote. 737f219e013SMasahiro Yamada end = s.find(c, i) 738f219e013SMasahiro Yamada if end == -1: 739f219e013SMasahiro Yamada _tokenization_error(s, strlen, filename, linenr) 740f219e013SMasahiro Yamada append(s[i:end]) 741f219e013SMasahiro Yamada i = end + 1 742f219e013SMasahiro Yamada 743f219e013SMasahiro Yamada elif c == "&": 744f219e013SMasahiro Yamada if i + 1 >= strlen: 745f219e013SMasahiro Yamada # Invalid characters are ignored 746f219e013SMasahiro Yamada continue 747f219e013SMasahiro Yamada if s[i + 1] != "&": 748f219e013SMasahiro Yamada # Invalid characters are ignored 749f219e013SMasahiro Yamada i += 1 750f219e013SMasahiro Yamada continue 751f219e013SMasahiro Yamada append(T_AND) 752f219e013SMasahiro Yamada i += 2 753f219e013SMasahiro Yamada 754f219e013SMasahiro Yamada elif c == "|": 755f219e013SMasahiro Yamada if i + 1 >= strlen: 756f219e013SMasahiro Yamada # Invalid characters are ignored 757f219e013SMasahiro Yamada continue 758f219e013SMasahiro Yamada if s[i + 1] != "|": 759f219e013SMasahiro Yamada # Invalid characters are ignored 760f219e013SMasahiro Yamada i += 1 761f219e013SMasahiro Yamada continue 762f219e013SMasahiro Yamada append(T_OR) 763f219e013SMasahiro Yamada i += 2 764f219e013SMasahiro Yamada 765f219e013SMasahiro Yamada elif c == "!": 766f219e013SMasahiro Yamada if i + 1 >= strlen: 767f219e013SMasahiro Yamada _tokenization_error(s, strlen, filename, linenr) 768f219e013SMasahiro Yamada if s[i + 1] == "=": 769f219e013SMasahiro Yamada append(T_UNEQUAL) 770f219e013SMasahiro Yamada i += 2 771f219e013SMasahiro Yamada else: 772f219e013SMasahiro Yamada append(T_NOT) 773f219e013SMasahiro Yamada i += 1 774f219e013SMasahiro Yamada 775f219e013SMasahiro Yamada elif c == "=": 776f219e013SMasahiro Yamada append(T_EQUAL) 777f219e013SMasahiro Yamada i += 1 778f219e013SMasahiro Yamada 779f219e013SMasahiro Yamada elif c == "(": 780f219e013SMasahiro Yamada append(T_OPEN_PAREN) 781f219e013SMasahiro Yamada i += 1 782f219e013SMasahiro Yamada 783f219e013SMasahiro Yamada elif c == ")": 784f219e013SMasahiro Yamada append(T_CLOSE_PAREN) 785f219e013SMasahiro Yamada i += 1 786f219e013SMasahiro Yamada 787f219e013SMasahiro Yamada elif c == "#": 788f219e013SMasahiro Yamada break 789f219e013SMasahiro Yamada 790f219e013SMasahiro Yamada else: 791f219e013SMasahiro Yamada # Invalid characters are ignored 792f219e013SMasahiro Yamada i += 1 793f219e013SMasahiro Yamada continue 794f219e013SMasahiro Yamada 795f219e013SMasahiro Yamada previous = tokens[-1] 796f219e013SMasahiro Yamada 797f219e013SMasahiro Yamada return _Feed(tokens) 798f219e013SMasahiro Yamada 799f219e013SMasahiro Yamada # 800f219e013SMasahiro Yamada # Parsing 801f219e013SMasahiro Yamada # 802f219e013SMasahiro Yamada 803f219e013SMasahiro Yamada # Expression grammar: 804f219e013SMasahiro Yamada # 805f219e013SMasahiro Yamada # <expr> -> <symbol> 806f219e013SMasahiro Yamada # <symbol> '=' <symbol> 807f219e013SMasahiro Yamada # <symbol> '!=' <symbol> 808f219e013SMasahiro Yamada # '(' <expr> ')' 809f219e013SMasahiro Yamada # '!' <expr> 810f219e013SMasahiro Yamada # <expr> '&&' <expr> 811f219e013SMasahiro Yamada # <expr> '||' <expr> 812f219e013SMasahiro Yamada 813f219e013SMasahiro Yamada def _parse_expr(self, 814f219e013SMasahiro Yamada feed, 815f219e013SMasahiro Yamada cur_sym_or_choice, 816f219e013SMasahiro Yamada line, 817f219e013SMasahiro Yamada filename = None, 818f219e013SMasahiro Yamada linenr = None, 819f219e013SMasahiro Yamada transform_m = True): 820f219e013SMasahiro Yamada """Parse an expression from the tokens in 'feed' using a simple 821f219e013SMasahiro Yamada top-down approach. The result has the form (<operator>, <list 822f219e013SMasahiro Yamada containing parsed operands>). 823f219e013SMasahiro Yamada 824f219e013SMasahiro Yamada feed -- _Feed instance containing the tokens for the expression. 825f219e013SMasahiro Yamada 826f219e013SMasahiro Yamada cur_sym_or_choice -- The symbol or choice currently being parsed, or 827f219e013SMasahiro Yamada None if we're not parsing a symbol or choice. 828f219e013SMasahiro Yamada Used for recording references to symbols. 829f219e013SMasahiro Yamada 830f219e013SMasahiro Yamada line -- The line containing the expression being parsed. 831f219e013SMasahiro Yamada 832f219e013SMasahiro Yamada filename (default: None) -- The file containing the expression. 833f219e013SMasahiro Yamada 834f219e013SMasahiro Yamada linenr (default: None) -- The line number containing the expression. 835f219e013SMasahiro Yamada 836f219e013SMasahiro Yamada transform_m (default: False) -- Determines if 'm' should be rewritten to 837f219e013SMasahiro Yamada 'm && MODULES' -- see 838f219e013SMasahiro Yamada parse_val_and_cond().""" 839f219e013SMasahiro Yamada 840f219e013SMasahiro Yamada # Use instance variables to avoid having to pass these as arguments 841f219e013SMasahiro Yamada # through the top-down parser in _parse_expr_2(), which is tedious and 842f219e013SMasahiro Yamada # obfuscates the code. A profiler run shows no noticeable performance 843f219e013SMasahiro Yamada # difference. 844f219e013SMasahiro Yamada self.parse_expr_cur_sym_or_choice = cur_sym_or_choice 845f219e013SMasahiro Yamada self.parse_expr_line = line 846f219e013SMasahiro Yamada self.parse_expr_filename = filename 847f219e013SMasahiro Yamada self.parse_expr_linenr = linenr 848f219e013SMasahiro Yamada self.parse_expr_transform_m = transform_m 849f219e013SMasahiro Yamada 850f219e013SMasahiro Yamada return self._parse_expr_2(feed) 851f219e013SMasahiro Yamada 852f219e013SMasahiro Yamada def _parse_expr_2(self, feed): 853f219e013SMasahiro Yamada or_terms = [self._parse_or_term(feed)] 854f219e013SMasahiro Yamada # Keep parsing additional terms while the lookahead is '||' 855f219e013SMasahiro Yamada while feed.check(T_OR): 856f219e013SMasahiro Yamada or_terms.append(self._parse_or_term(feed)) 857f219e013SMasahiro Yamada 858f219e013SMasahiro Yamada return or_terms[0] if len(or_terms) == 1 else (OR, or_terms) 859f219e013SMasahiro Yamada 860f219e013SMasahiro Yamada def _parse_or_term(self, feed): 861f219e013SMasahiro Yamada and_terms = [self._parse_factor(feed)] 862f219e013SMasahiro Yamada # Keep parsing additional terms while the lookahead is '&&' 863f219e013SMasahiro Yamada while feed.check(T_AND): 864f219e013SMasahiro Yamada and_terms.append(self._parse_factor(feed)) 865f219e013SMasahiro Yamada 866f219e013SMasahiro Yamada return and_terms[0] if len(and_terms) == 1 else (AND, and_terms) 867f219e013SMasahiro Yamada 868f219e013SMasahiro Yamada def _parse_factor(self, feed): 869f219e013SMasahiro Yamada if feed.check(T_OPEN_PAREN): 870f219e013SMasahiro Yamada expr_parse = self._parse_expr_2(feed) 871f219e013SMasahiro Yamada 872f219e013SMasahiro Yamada if not feed.check(T_CLOSE_PAREN): 873f219e013SMasahiro Yamada _parse_error(self.parse_expr_line, 874f219e013SMasahiro Yamada "missing end parenthesis.", 875f219e013SMasahiro Yamada self.parse_expr_filename, 876f219e013SMasahiro Yamada self.parse_expr_linenr) 877f219e013SMasahiro Yamada 878f219e013SMasahiro Yamada return expr_parse 879f219e013SMasahiro Yamada 880f219e013SMasahiro Yamada if feed.check(T_NOT): 881f219e013SMasahiro Yamada return (NOT, self._parse_factor(feed)) 882f219e013SMasahiro Yamada 883f219e013SMasahiro Yamada sym_or_string = feed.get_next() 884f219e013SMasahiro Yamada 885f219e013SMasahiro Yamada if not isinstance(sym_or_string, (Symbol, str)): 886f219e013SMasahiro Yamada _parse_error(self.parse_expr_line, 887f219e013SMasahiro Yamada "malformed expression.", 888f219e013SMasahiro Yamada self.parse_expr_filename, 889f219e013SMasahiro Yamada self.parse_expr_linenr) 890f219e013SMasahiro Yamada 891f219e013SMasahiro Yamada if self.parse_expr_cur_sym_or_choice is not None and \ 892f219e013SMasahiro Yamada isinstance(sym_or_string, Symbol): 893f219e013SMasahiro Yamada self.parse_expr_cur_sym_or_choice.referenced_syms.add(sym_or_string) 894f219e013SMasahiro Yamada 895f219e013SMasahiro Yamada next_token = feed.peek_next() 896f219e013SMasahiro Yamada 897f219e013SMasahiro Yamada # For conditional expressions ('depends on <expr>', '... if <expr>', 898f219e013SMasahiro Yamada # etc.), "m" and m are rewritten to "m" && MODULES. 899f219e013SMasahiro Yamada if next_token != T_EQUAL and next_token != T_UNEQUAL: 900f219e013SMasahiro Yamada if self.parse_expr_transform_m and (sym_or_string is self.m or 901f219e013SMasahiro Yamada sym_or_string == "m"): 902f219e013SMasahiro Yamada return (AND, ["m", self._sym_lookup("MODULES")]) 903f219e013SMasahiro Yamada return sym_or_string 904f219e013SMasahiro Yamada 905f219e013SMasahiro Yamada relation = EQUAL if (feed.get_next() == T_EQUAL) else UNEQUAL 906f219e013SMasahiro Yamada sym_or_string_2 = feed.get_next() 907f219e013SMasahiro Yamada 908f219e013SMasahiro Yamada if self.parse_expr_cur_sym_or_choice is not None and \ 909f219e013SMasahiro Yamada isinstance(sym_or_string_2, Symbol): 910f219e013SMasahiro Yamada self.parse_expr_cur_sym_or_choice.referenced_syms.add(sym_or_string_2) 911f219e013SMasahiro Yamada 912f219e013SMasahiro Yamada if sym_or_string is self.m: 913f219e013SMasahiro Yamada sym_or_string = "m" 914f219e013SMasahiro Yamada 915f219e013SMasahiro Yamada if sym_or_string_2 is self.m: 916f219e013SMasahiro Yamada sym_or_string_2 = "m" 917f219e013SMasahiro Yamada 918f219e013SMasahiro Yamada return (relation, sym_or_string, sym_or_string_2) 919f219e013SMasahiro Yamada 920f219e013SMasahiro Yamada def _parse_file(self, filename, parent, deps, visible_if_deps, res = None): 921f219e013SMasahiro Yamada """Parse the Kconfig file 'filename'. The result is a _Block with all 922f219e013SMasahiro Yamada items from the file. See _parse_block() for the meaning of the 923f219e013SMasahiro Yamada parameters.""" 924f219e013SMasahiro Yamada line_feeder = _FileFeed(_get_lines(filename), filename) 925f219e013SMasahiro Yamada return self._parse_block(line_feeder, None, parent, deps, visible_if_deps, res) 926f219e013SMasahiro Yamada 927f219e013SMasahiro Yamada def _parse_block(self, line_feeder, end_marker, parent, deps, 928f219e013SMasahiro Yamada visible_if_deps = None, res = None): 929f219e013SMasahiro Yamada """Parses a block, which is the contents of either a file or an if, 930f219e013SMasahiro Yamada menu, or choice statement. The result is a _Block with the items from 931f219e013SMasahiro Yamada the block. 932f219e013SMasahiro Yamada 933f219e013SMasahiro Yamada end_marker -- The token that ends the block, e.g. T_ENDIF ("endif") for 934f219e013SMasahiro Yamada if's. None for files. 935f219e013SMasahiro Yamada 936f219e013SMasahiro Yamada parent -- The enclosing menu, choice or if, or None if we're at the top 937f219e013SMasahiro Yamada level. 938f219e013SMasahiro Yamada 939f219e013SMasahiro Yamada deps -- Dependencies from enclosing menus, choices and if's. 940f219e013SMasahiro Yamada 941f219e013SMasahiro Yamada visible_if_deps (default: None) -- 'visible if' dependencies from 942f219e013SMasahiro Yamada enclosing menus. 943f219e013SMasahiro Yamada 944f219e013SMasahiro Yamada res (default: None) -- The _Block to add items to. If None, a new 945f219e013SMasahiro Yamada _Block is created to hold the items.""" 946f219e013SMasahiro Yamada 947f219e013SMasahiro Yamada block = _Block() if res is None else res 948f219e013SMasahiro Yamada 949f219e013SMasahiro Yamada filename = line_feeder.get_filename() 950f219e013SMasahiro Yamada 951f219e013SMasahiro Yamada while 1: 952f219e013SMasahiro Yamada 953f219e013SMasahiro Yamada # Do we already have a tokenized line that we determined wasn't 954f219e013SMasahiro Yamada # part of whatever we were parsing earlier? See comment in 955f219e013SMasahiro Yamada # Config.__init__(). 956f219e013SMasahiro Yamada if self.end_line is not None: 957f219e013SMasahiro Yamada assert self.end_line_tokens is not None 958f219e013SMasahiro Yamada tokens = self.end_line_tokens 959f219e013SMasahiro Yamada tokens.go_to_start() 960f219e013SMasahiro Yamada 961f219e013SMasahiro Yamada line = self.end_line 962f219e013SMasahiro Yamada linenr = line_feeder.get_linenr() 963f219e013SMasahiro Yamada 964f219e013SMasahiro Yamada self.end_line = None 965f219e013SMasahiro Yamada self.end_line_tokens = None 966f219e013SMasahiro Yamada 967f219e013SMasahiro Yamada else: 968f219e013SMasahiro Yamada line = line_feeder.get_next() 969f219e013SMasahiro Yamada if line is None: 970f219e013SMasahiro Yamada if end_marker is not None: 971f219e013SMasahiro Yamada raise Kconfig_Syntax_Error, ( 972f219e013SMasahiro Yamada "Unexpected end of file {0}." 973f219e013SMasahiro Yamada .format(line_feeder.get_filename())) 974f219e013SMasahiro Yamada return block 975f219e013SMasahiro Yamada 976f219e013SMasahiro Yamada linenr = line_feeder.get_linenr() 977f219e013SMasahiro Yamada 978f219e013SMasahiro Yamada tokens = self._tokenize(line, False, filename, linenr) 979f219e013SMasahiro Yamada 980f219e013SMasahiro Yamada if tokens.is_empty(): 981f219e013SMasahiro Yamada continue 982f219e013SMasahiro Yamada 983f219e013SMasahiro Yamada t0 = tokens.get_next() 984f219e013SMasahiro Yamada 985f219e013SMasahiro Yamada # Have we reached the end of the block? 986f219e013SMasahiro Yamada if t0 == end_marker: 987f219e013SMasahiro Yamada return block 988f219e013SMasahiro Yamada 989f219e013SMasahiro Yamada if t0 == T_CONFIG or t0 == T_MENUCONFIG: 990f219e013SMasahiro Yamada # The tokenizer will automatically allocate a new Symbol object 991f219e013SMasahiro Yamada # for any new names it encounters, so we don't need to worry 992f219e013SMasahiro Yamada # about that here. 993f219e013SMasahiro Yamada sym = tokens.get_next() 994f219e013SMasahiro Yamada 995f219e013SMasahiro Yamada # Symbols defined in multiple places get the parent of their 996f219e013SMasahiro Yamada # first definition. However, for symbols whose parents are choice 997f219e013SMasahiro Yamada # statements, the choice statement takes precedence. 998f219e013SMasahiro Yamada if not sym.is_defined_ or isinstance(parent, Choice): 999f219e013SMasahiro Yamada sym.parent = parent 1000f219e013SMasahiro Yamada 1001f219e013SMasahiro Yamada sym.is_defined_ = True 1002f219e013SMasahiro Yamada 1003f219e013SMasahiro Yamada self.kconfig_syms.append(sym) 1004f219e013SMasahiro Yamada block.add_item(sym) 1005f219e013SMasahiro Yamada 1006f219e013SMasahiro Yamada self._parse_properties(line_feeder, sym, deps, visible_if_deps) 1007f219e013SMasahiro Yamada 1008f219e013SMasahiro Yamada elif t0 == T_MENU: 1009f219e013SMasahiro Yamada menu = Menu() 1010f219e013SMasahiro Yamada self.menus.append(menu) 1011f219e013SMasahiro Yamada menu.config = self 1012f219e013SMasahiro Yamada menu.parent = parent 1013f219e013SMasahiro Yamada menu.title = tokens.get_next() 1014f219e013SMasahiro Yamada 1015f219e013SMasahiro Yamada menu.filename = filename 1016f219e013SMasahiro Yamada menu.linenr = linenr 1017f219e013SMasahiro Yamada 1018f219e013SMasahiro Yamada # Parse properties and contents 1019f219e013SMasahiro Yamada self._parse_properties(line_feeder, menu, deps, visible_if_deps) 1020f219e013SMasahiro Yamada menu.block = self._parse_block(line_feeder, 1021f219e013SMasahiro Yamada T_ENDMENU, 1022f219e013SMasahiro Yamada menu, 1023f219e013SMasahiro Yamada menu.dep_expr, 1024f219e013SMasahiro Yamada _make_and(visible_if_deps, 1025f219e013SMasahiro Yamada menu.visible_if_expr)) 1026f219e013SMasahiro Yamada 1027f219e013SMasahiro Yamada block.add_item(menu) 1028f219e013SMasahiro Yamada 1029f219e013SMasahiro Yamada elif t0 == T_IF: 1030f219e013SMasahiro Yamada # If statements are treated as syntactic sugar for adding 1031f219e013SMasahiro Yamada # dependencies to enclosed items and do not have an explicit 1032f219e013SMasahiro Yamada # object representation. 1033f219e013SMasahiro Yamada 1034f219e013SMasahiro Yamada dep_expr = self._parse_expr(tokens, None, line, filename, linenr) 1035f219e013SMasahiro Yamada self._parse_block(line_feeder, 1036f219e013SMasahiro Yamada T_ENDIF, 1037f219e013SMasahiro Yamada parent, 1038f219e013SMasahiro Yamada _make_and(dep_expr, deps), 1039f219e013SMasahiro Yamada visible_if_deps, 1040f219e013SMasahiro Yamada block) # Add items to the same block 1041f219e013SMasahiro Yamada 1042f219e013SMasahiro Yamada elif t0 == T_CHOICE: 1043f219e013SMasahiro Yamada # We support named choices 1044f219e013SMasahiro Yamada already_defined = False 1045f219e013SMasahiro Yamada name = None 1046f219e013SMasahiro Yamada if len(tokens) > 1 and isinstance(tokens[1], str): 1047f219e013SMasahiro Yamada name = tokens[1] 1048f219e013SMasahiro Yamada already_defined = name in self.named_choices 1049f219e013SMasahiro Yamada 1050f219e013SMasahiro Yamada if already_defined: 1051f219e013SMasahiro Yamada choice = self.named_choices[name] 1052f219e013SMasahiro Yamada else: 1053f219e013SMasahiro Yamada choice = Choice() 1054f219e013SMasahiro Yamada self.choices.append(choice) 1055f219e013SMasahiro Yamada if name is not None: 1056f219e013SMasahiro Yamada choice.name = name 1057f219e013SMasahiro Yamada self.named_choices[name] = choice 1058f219e013SMasahiro Yamada 1059f219e013SMasahiro Yamada choice.config = self 1060f219e013SMasahiro Yamada choice.parent = parent 1061f219e013SMasahiro Yamada 1062f219e013SMasahiro Yamada choice.def_locations.append((filename, linenr)) 1063f219e013SMasahiro Yamada 1064f219e013SMasahiro Yamada # Parse properties and contents 1065f219e013SMasahiro Yamada self._parse_properties(line_feeder, choice, deps, visible_if_deps) 1066f219e013SMasahiro Yamada choice.block = self._parse_block(line_feeder, 1067f219e013SMasahiro Yamada T_ENDCHOICE, 1068f219e013SMasahiro Yamada choice, 1069f219e013SMasahiro Yamada None, 1070f219e013SMasahiro Yamada visible_if_deps) 1071f219e013SMasahiro Yamada 1072f219e013SMasahiro Yamada choice._determine_actual_symbols() 1073f219e013SMasahiro Yamada 1074f219e013SMasahiro Yamada # If no type is set for the choice, its type is that of the first 1075f219e013SMasahiro Yamada # choice item 1076f219e013SMasahiro Yamada if choice.type == UNKNOWN: 1077f219e013SMasahiro Yamada for item in choice.get_symbols(): 1078f219e013SMasahiro Yamada if item.type != UNKNOWN: 1079f219e013SMasahiro Yamada choice.type = item.type 1080f219e013SMasahiro Yamada break 1081f219e013SMasahiro Yamada 1082f219e013SMasahiro Yamada # Each choice item of UNKNOWN type gets the type of the choice 1083f219e013SMasahiro Yamada for item in choice.get_symbols(): 1084f219e013SMasahiro Yamada if item.type == UNKNOWN: 1085f219e013SMasahiro Yamada item.type = choice.type 1086f219e013SMasahiro Yamada 1087f219e013SMasahiro Yamada # For named choices defined in multiple locations, only record 1088f219e013SMasahiro Yamada # at the first definition 1089f219e013SMasahiro Yamada if not already_defined: 1090f219e013SMasahiro Yamada block.add_item(choice) 1091f219e013SMasahiro Yamada 1092f219e013SMasahiro Yamada elif t0 == T_COMMENT: 1093f219e013SMasahiro Yamada comment = Comment() 1094f219e013SMasahiro Yamada comment.config = self 1095f219e013SMasahiro Yamada comment.parent = parent 1096f219e013SMasahiro Yamada 1097f219e013SMasahiro Yamada comment.filename = filename 1098f219e013SMasahiro Yamada comment.linenr = linenr 1099f219e013SMasahiro Yamada 1100f219e013SMasahiro Yamada comment.text = tokens.get_next() 1101f219e013SMasahiro Yamada self._parse_properties(line_feeder, comment, deps, visible_if_deps) 1102f219e013SMasahiro Yamada 1103f219e013SMasahiro Yamada block.add_item(comment) 1104f219e013SMasahiro Yamada self.comments.append(comment) 1105f219e013SMasahiro Yamada 1106f219e013SMasahiro Yamada elif t0 == T_SOURCE: 1107f219e013SMasahiro Yamada kconfig_file = tokens.get_next() 1108f219e013SMasahiro Yamada exp_kconfig_file = self._expand_sym_refs(kconfig_file) 1109f219e013SMasahiro Yamada f = os.path.join(self.base_dir, exp_kconfig_file) 1110f219e013SMasahiro Yamada 1111f219e013SMasahiro Yamada if not os.path.exists(f): 1112f219e013SMasahiro Yamada raise IOError, ('{0}:{1}: sourced file "{2}" (expands to\n' 1113f219e013SMasahiro Yamada '"{3}") not found. Perhaps base_dir\n' 1114f219e013SMasahiro Yamada '(argument to Config.__init__(), currently\n' 1115f219e013SMasahiro Yamada '"{4}") is set to the wrong value.' 1116f219e013SMasahiro Yamada .format(filename, 1117f219e013SMasahiro Yamada linenr, 1118f219e013SMasahiro Yamada kconfig_file, 1119f219e013SMasahiro Yamada exp_kconfig_file, 1120f219e013SMasahiro Yamada self.base_dir)) 1121f219e013SMasahiro Yamada 1122f219e013SMasahiro Yamada # Add items to the same block 1123f219e013SMasahiro Yamada self._parse_file(f, parent, deps, visible_if_deps, block) 1124f219e013SMasahiro Yamada 1125f219e013SMasahiro Yamada elif t0 == T_MAINMENU: 1126f219e013SMasahiro Yamada text = tokens.get_next() 1127f219e013SMasahiro Yamada 1128f219e013SMasahiro Yamada if self.mainmenu_text is not None: 1129f219e013SMasahiro Yamada self._warn("overriding 'mainmenu' text. " 1130f219e013SMasahiro Yamada 'Old value: "{0}", new value: "{1}".' 1131f219e013SMasahiro Yamada .format(self.mainmenu_text, text), 1132f219e013SMasahiro Yamada filename, 1133f219e013SMasahiro Yamada linenr) 1134f219e013SMasahiro Yamada 1135f219e013SMasahiro Yamada self.mainmenu_text = text 1136f219e013SMasahiro Yamada 1137f219e013SMasahiro Yamada else: 1138f219e013SMasahiro Yamada _parse_error(line, "unrecognized construct.", filename, linenr) 1139f219e013SMasahiro Yamada 1140f219e013SMasahiro Yamada def _parse_properties(self, line_feeder, stmt, deps, visible_if_deps): 1141f219e013SMasahiro Yamada """Parsing of properties for symbols, menus, choices, and comments.""" 1142f219e013SMasahiro Yamada 1143f219e013SMasahiro Yamada def parse_val_and_cond(tokens, line, filename, linenr): 1144f219e013SMasahiro Yamada """Parses '<expr1> if <expr2>' constructs, where the 'if' part is 1145f219e013SMasahiro Yamada optional. Returns a tuple containing the parsed expressions, with 1146f219e013SMasahiro Yamada None as the second element if the 'if' part is missing.""" 1147f219e013SMasahiro Yamada val = self._parse_expr(tokens, stmt, line, filename, linenr, False) 1148f219e013SMasahiro Yamada 1149f219e013SMasahiro Yamada if tokens.check(T_IF): 1150f219e013SMasahiro Yamada return (val, self._parse_expr(tokens, stmt, line, filename, linenr)) 1151f219e013SMasahiro Yamada 1152f219e013SMasahiro Yamada return (val, None) 1153f219e013SMasahiro Yamada 1154f219e013SMasahiro Yamada # In case the symbol is defined in multiple locations, we need to 1155f219e013SMasahiro Yamada # remember what prompts, defaults, and selects are new for this 1156f219e013SMasahiro Yamada # definition, as "depends on" should only apply to the local 1157f219e013SMasahiro Yamada # definition. 1158f219e013SMasahiro Yamada new_prompt = None 1159f219e013SMasahiro Yamada new_def_exprs = [] 1160f219e013SMasahiro Yamada new_selects = [] 1161f219e013SMasahiro Yamada 1162f219e013SMasahiro Yamada # Dependencies from 'depends on' statements 1163f219e013SMasahiro Yamada depends_on_expr = None 1164f219e013SMasahiro Yamada 1165f219e013SMasahiro Yamada while 1: 1166f219e013SMasahiro Yamada line = line_feeder.get_next() 1167f219e013SMasahiro Yamada if line is None: 1168f219e013SMasahiro Yamada break 1169f219e013SMasahiro Yamada 1170f219e013SMasahiro Yamada filename = line_feeder.get_filename() 1171f219e013SMasahiro Yamada linenr = line_feeder.get_linenr() 1172f219e013SMasahiro Yamada 1173f219e013SMasahiro Yamada tokens = self._tokenize(line, False, filename, linenr) 1174f219e013SMasahiro Yamada 1175f219e013SMasahiro Yamada if tokens.is_empty(): 1176f219e013SMasahiro Yamada continue 1177f219e013SMasahiro Yamada 1178f219e013SMasahiro Yamada t0 = tokens.get_next() 1179f219e013SMasahiro Yamada 1180f219e013SMasahiro Yamada if t0 == T_HELP: 1181f219e013SMasahiro Yamada # Find first non-empty line and get its indentation 1182f219e013SMasahiro Yamada 1183f219e013SMasahiro Yamada line_feeder.remove_while(str.isspace) 1184f219e013SMasahiro Yamada line = line_feeder.get_next() 1185f219e013SMasahiro Yamada 1186f219e013SMasahiro Yamada if line is None: 1187f219e013SMasahiro Yamada stmt.help = "" 1188f219e013SMasahiro Yamada break 1189f219e013SMasahiro Yamada 1190f219e013SMasahiro Yamada indent = _indentation(line) 1191f219e013SMasahiro Yamada 1192f219e013SMasahiro Yamada # If the first non-empty lines has zero indent, there is no 1193f219e013SMasahiro Yamada # help text 1194f219e013SMasahiro Yamada if indent == 0: 1195f219e013SMasahiro Yamada stmt.help = "" 1196f219e013SMasahiro Yamada line_feeder.go_back() 1197f219e013SMasahiro Yamada break 1198f219e013SMasahiro Yamada 1199f219e013SMasahiro Yamada help_lines = [_deindent(line, indent)] 1200f219e013SMasahiro Yamada 1201f219e013SMasahiro Yamada # The help text goes on till the first non-empty line with less 1202f219e013SMasahiro Yamada # indent 1203f219e013SMasahiro Yamada while 1: 1204f219e013SMasahiro Yamada line = line_feeder.get_next() 1205f219e013SMasahiro Yamada if (line is None) or \ 1206f219e013SMasahiro Yamada (not line.isspace() and _indentation(line) < indent): 1207f219e013SMasahiro Yamada stmt.help = "".join(help_lines) 1208f219e013SMasahiro Yamada break 1209f219e013SMasahiro Yamada 1210f219e013SMasahiro Yamada help_lines.append(_deindent(line, indent)) 1211f219e013SMasahiro Yamada 1212f219e013SMasahiro Yamada if line is None: 1213f219e013SMasahiro Yamada break 1214f219e013SMasahiro Yamada 1215f219e013SMasahiro Yamada line_feeder.go_back() 1216f219e013SMasahiro Yamada 1217f219e013SMasahiro Yamada elif t0 == T_PROMPT: 1218f219e013SMasahiro Yamada # 'prompt' properties override each other within a single 1219f219e013SMasahiro Yamada # definition of a symbol, but additional prompts can be added 1220f219e013SMasahiro Yamada # by defining the symbol multiple times; hence 'new_prompt' 1221f219e013SMasahiro Yamada # instead of 'prompt'. 1222f219e013SMasahiro Yamada new_prompt = parse_val_and_cond(tokens, line, filename, linenr) 1223f219e013SMasahiro Yamada 1224f219e013SMasahiro Yamada elif t0 == T_DEFAULT: 1225f219e013SMasahiro Yamada new_def_exprs.append(parse_val_and_cond(tokens, line, filename, linenr)) 1226f219e013SMasahiro Yamada 1227f219e013SMasahiro Yamada elif t0 == T_DEPENDS: 1228f219e013SMasahiro Yamada if not tokens.check(T_ON): 1229f219e013SMasahiro Yamada _parse_error(line, 'expected "on" after "depends".', filename, linenr) 1230f219e013SMasahiro Yamada 1231f219e013SMasahiro Yamada parsed_deps = self._parse_expr(tokens, stmt, line, filename, linenr) 1232f219e013SMasahiro Yamada 1233f219e013SMasahiro Yamada if isinstance(stmt, (Menu, Comment)): 1234f219e013SMasahiro Yamada stmt.dep_expr = _make_and(stmt.dep_expr, parsed_deps) 1235f219e013SMasahiro Yamada else: 1236f219e013SMasahiro Yamada depends_on_expr = _make_and(depends_on_expr, parsed_deps) 1237f219e013SMasahiro Yamada 1238f219e013SMasahiro Yamada elif t0 == T_VISIBLE: 1239f219e013SMasahiro Yamada if not tokens.check(T_IF): 1240f219e013SMasahiro Yamada _parse_error(line, 'expected "if" after "visible".', filename, linenr) 1241f219e013SMasahiro Yamada if not isinstance(stmt, Menu): 1242f219e013SMasahiro Yamada _parse_error(line, 1243f219e013SMasahiro Yamada "'visible if' is only valid for menus.", 1244f219e013SMasahiro Yamada filename, 1245f219e013SMasahiro Yamada linenr) 1246f219e013SMasahiro Yamada 1247f219e013SMasahiro Yamada parsed_deps = self._parse_expr(tokens, stmt, line, filename, linenr) 1248f219e013SMasahiro Yamada stmt.visible_if_expr = _make_and(stmt.visible_if_expr, parsed_deps) 1249f219e013SMasahiro Yamada 1250f219e013SMasahiro Yamada elif t0 == T_SELECT: 1251f219e013SMasahiro Yamada target = tokens.get_next() 1252f219e013SMasahiro Yamada 1253f219e013SMasahiro Yamada stmt.referenced_syms.add(target) 1254f219e013SMasahiro Yamada stmt.selected_syms.add(target) 1255f219e013SMasahiro Yamada 1256f219e013SMasahiro Yamada if tokens.check(T_IF): 1257f219e013SMasahiro Yamada new_selects.append((target, 1258f219e013SMasahiro Yamada self._parse_expr(tokens, stmt, line, filename, linenr))) 1259f219e013SMasahiro Yamada else: 1260f219e013SMasahiro Yamada new_selects.append((target, None)) 1261f219e013SMasahiro Yamada 1262f219e013SMasahiro Yamada elif t0 in (T_BOOL, T_TRISTATE, T_INT, T_HEX, T_STRING): 1263f219e013SMasahiro Yamada stmt.type = token_to_type[t0] 1264f219e013SMasahiro Yamada 1265f219e013SMasahiro Yamada if len(tokens) > 1: 1266f219e013SMasahiro Yamada new_prompt = parse_val_and_cond(tokens, line, filename, linenr) 1267f219e013SMasahiro Yamada 1268f219e013SMasahiro Yamada elif t0 == T_RANGE: 1269f219e013SMasahiro Yamada lower = tokens.get_next() 1270f219e013SMasahiro Yamada upper = tokens.get_next() 1271f219e013SMasahiro Yamada stmt.referenced_syms.add(lower) 1272f219e013SMasahiro Yamada stmt.referenced_syms.add(upper) 1273f219e013SMasahiro Yamada 1274f219e013SMasahiro Yamada if tokens.check(T_IF): 1275f219e013SMasahiro Yamada stmt.ranges.append((lower, upper, 1276f219e013SMasahiro Yamada self._parse_expr(tokens, stmt, line, filename, linenr))) 1277f219e013SMasahiro Yamada else: 1278f219e013SMasahiro Yamada stmt.ranges.append((lower, upper, None)) 1279f219e013SMasahiro Yamada 1280f219e013SMasahiro Yamada elif t0 == T_DEF_BOOL: 1281f219e013SMasahiro Yamada stmt.type = BOOL 1282f219e013SMasahiro Yamada 1283f219e013SMasahiro Yamada if len(tokens) > 1: 1284f219e013SMasahiro Yamada new_def_exprs.append(parse_val_and_cond(tokens, line, filename, linenr)) 1285f219e013SMasahiro Yamada 1286f219e013SMasahiro Yamada elif t0 == T_DEF_TRISTATE: 1287f219e013SMasahiro Yamada stmt.type = TRISTATE 1288f219e013SMasahiro Yamada 1289f219e013SMasahiro Yamada if len(tokens) > 1: 1290f219e013SMasahiro Yamada new_def_exprs.append(parse_val_and_cond(tokens, line, filename, linenr)) 1291f219e013SMasahiro Yamada 1292f219e013SMasahiro Yamada elif t0 == T_OPTIONAL: 1293f219e013SMasahiro Yamada if not isinstance(stmt, Choice): 1294f219e013SMasahiro Yamada _parse_error(line, 1295f219e013SMasahiro Yamada '"optional" is only valid for choices.', 1296f219e013SMasahiro Yamada filename, 1297f219e013SMasahiro Yamada linenr) 1298f219e013SMasahiro Yamada stmt.optional = True 1299f219e013SMasahiro Yamada 1300f219e013SMasahiro Yamada elif t0 == T_OPTION: 1301f219e013SMasahiro Yamada if tokens.check(T_ENV) and tokens.check(T_EQUAL): 1302f219e013SMasahiro Yamada env_var = tokens.get_next() 1303f219e013SMasahiro Yamada 1304f219e013SMasahiro Yamada stmt.is_special_ = True 1305f219e013SMasahiro Yamada stmt.is_from_env = True 1306f219e013SMasahiro Yamada 1307f219e013SMasahiro Yamada if env_var not in os.environ: 1308f219e013SMasahiro Yamada self._warn(""" 1309f219e013SMasahiro YamadaThe symbol {0} references the non-existent environment variable {1} and will 1310f219e013SMasahiro Yamadaget the empty string as its value. 1311f219e013SMasahiro Yamada 1312f219e013SMasahiro YamadaIf you're using kconfiglib via 'make (i)scriptconfig' it should have set up the 1313f219e013SMasahiro Yamadaenvironment correctly for you. If you still got this message, that might be an 1314f219e013SMasahiro Yamadaerror, and you should e-mail kconfiglib@gmail.com. 1315f219e013SMasahiro Yamada.""" .format(stmt.name, env_var), 1316f219e013SMasahiro Yamada filename, 1317f219e013SMasahiro Yamada linenr) 1318f219e013SMasahiro Yamada 1319f219e013SMasahiro Yamada stmt.cached_value = "" 1320f219e013SMasahiro Yamada else: 1321f219e013SMasahiro Yamada stmt.cached_value = os.environ[env_var] 1322f219e013SMasahiro Yamada 1323f219e013SMasahiro Yamada elif tokens.check(T_DEFCONFIG_LIST): 1324f219e013SMasahiro Yamada self.defconfig_sym = stmt 1325f219e013SMasahiro Yamada 1326f219e013SMasahiro Yamada elif tokens.check(T_MODULES): 1327f219e013SMasahiro Yamada self._warn("the 'modules' option is not supported. " 1328f219e013SMasahiro Yamada "Let me know if this is a problem for you; " 1329f219e013SMasahiro Yamada "it shouldn't be that hard to implement.", 1330f219e013SMasahiro Yamada filename, 1331f219e013SMasahiro Yamada linenr) 1332f219e013SMasahiro Yamada 1333f219e013SMasahiro Yamada else: 1334f219e013SMasahiro Yamada _parse_error(line, "unrecognized option.", filename, linenr) 1335f219e013SMasahiro Yamada 1336f219e013SMasahiro Yamada else: 1337f219e013SMasahiro Yamada # See comment in Config.__init__() 1338f219e013SMasahiro Yamada self.end_line = line 1339f219e013SMasahiro Yamada self.end_line_tokens = tokens 1340f219e013SMasahiro Yamada break 1341f219e013SMasahiro Yamada 1342f219e013SMasahiro Yamada # Propagate dependencies from enclosing menus and if's. 1343f219e013SMasahiro Yamada 1344f219e013SMasahiro Yamada # For menus and comments.. 1345f219e013SMasahiro Yamada if isinstance(stmt, (Menu, Comment)): 1346f219e013SMasahiro Yamada stmt.orig_deps = stmt.dep_expr 1347f219e013SMasahiro Yamada stmt.deps_from_containing = deps 1348f219e013SMasahiro Yamada stmt.dep_expr = _make_and(stmt.dep_expr, deps) 1349f219e013SMasahiro Yamada 1350f219e013SMasahiro Yamada stmt.all_referenced_syms = \ 1351f219e013SMasahiro Yamada stmt.referenced_syms | _get_expr_syms(deps) 1352f219e013SMasahiro Yamada 1353f219e013SMasahiro Yamada # For symbols and choices.. 1354f219e013SMasahiro Yamada else: 1355f219e013SMasahiro Yamada 1356f219e013SMasahiro Yamada # See comment for 'menu_dep' 1357f219e013SMasahiro Yamada stmt.menu_dep = depends_on_expr 1358f219e013SMasahiro Yamada 1359f219e013SMasahiro Yamada # Propagate dependencies specified with 'depends on' to any new 1360f219e013SMasahiro Yamada # default expressions, prompts, and selections. ("New" since a 1361f219e013SMasahiro Yamada # symbol might be defined in multiple places and the dependencies 1362f219e013SMasahiro Yamada # should only apply to the local definition.) 1363f219e013SMasahiro Yamada 1364f219e013SMasahiro Yamada new_def_exprs = [(val_expr, _make_and(cond_expr, depends_on_expr)) 1365f219e013SMasahiro Yamada for (val_expr, cond_expr) in new_def_exprs] 1366f219e013SMasahiro Yamada 1367f219e013SMasahiro Yamada new_selects = [(target, _make_and(cond_expr, depends_on_expr)) 1368f219e013SMasahiro Yamada for (target, cond_expr) in new_selects] 1369f219e013SMasahiro Yamada 1370f219e013SMasahiro Yamada if new_prompt is not None: 1371f219e013SMasahiro Yamada prompt, cond_expr = new_prompt 1372f219e013SMasahiro Yamada 1373f219e013SMasahiro Yamada # 'visible if' dependencies from enclosing menus get propagated 1374f219e013SMasahiro Yamada # to prompts 1375f219e013SMasahiro Yamada if visible_if_deps is not None: 1376f219e013SMasahiro Yamada cond_expr = _make_and(cond_expr, visible_if_deps) 1377f219e013SMasahiro Yamada 1378f219e013SMasahiro Yamada new_prompt = (prompt, _make_and(cond_expr, depends_on_expr)) 1379f219e013SMasahiro Yamada 1380f219e013SMasahiro Yamada # We save the original expressions -- before any menu and if 1381f219e013SMasahiro Yamada # conditions have been propagated -- so these can be retrieved 1382f219e013SMasahiro Yamada # later. 1383f219e013SMasahiro Yamada 1384f219e013SMasahiro Yamada stmt.orig_def_exprs.extend(new_def_exprs) 1385f219e013SMasahiro Yamada if new_prompt is not None: 1386f219e013SMasahiro Yamada stmt.orig_prompts.append(new_prompt) 1387f219e013SMasahiro Yamada 1388f219e013SMasahiro Yamada # Only symbols can select 1389f219e013SMasahiro Yamada if isinstance(stmt, Symbol): 1390f219e013SMasahiro Yamada stmt.orig_selects.extend(new_selects) 1391f219e013SMasahiro Yamada 1392f219e013SMasahiro Yamada # Save dependencies from enclosing menus and if's 1393f219e013SMasahiro Yamada stmt.deps_from_containing = deps 1394f219e013SMasahiro Yamada 1395f219e013SMasahiro Yamada # The set of symbols referenced directly by the symbol/choice plus 1396f219e013SMasahiro Yamada # all symbols referenced by enclosing menus and if's. 1397f219e013SMasahiro Yamada stmt.all_referenced_syms = \ 1398f219e013SMasahiro Yamada stmt.referenced_syms | _get_expr_syms(deps) 1399f219e013SMasahiro Yamada 1400f219e013SMasahiro Yamada # Propagate dependencies from enclosing menus and if's 1401f219e013SMasahiro Yamada 1402f219e013SMasahiro Yamada stmt.def_exprs.extend([(val_expr, _make_and(cond_expr, deps)) 1403f219e013SMasahiro Yamada for (val_expr, cond_expr) in new_def_exprs]) 1404f219e013SMasahiro Yamada 1405f219e013SMasahiro Yamada for (target, cond) in new_selects: 1406f219e013SMasahiro Yamada target.rev_dep = _make_or(target.rev_dep, 1407f219e013SMasahiro Yamada _make_and(stmt, 1408f219e013SMasahiro Yamada _make_and(cond, deps))) 1409f219e013SMasahiro Yamada 1410f219e013SMasahiro Yamada if new_prompt is not None: 1411f219e013SMasahiro Yamada prompt, cond_expr = new_prompt 1412f219e013SMasahiro Yamada stmt.prompts.append((prompt, _make_and(cond_expr, deps))) 1413f219e013SMasahiro Yamada 1414f219e013SMasahiro Yamada # 1415f219e013SMasahiro Yamada # Symbol table manipulation 1416f219e013SMasahiro Yamada # 1417f219e013SMasahiro Yamada 1418f219e013SMasahiro Yamada def _sym_lookup(self, name, add_sym_if_not_exists = True): 1419f219e013SMasahiro Yamada """Fetches the symbol 'name' from the symbol table, optionally adding 1420f219e013SMasahiro Yamada it if it does not exist (this is usually what we want).""" 1421f219e013SMasahiro Yamada if name in self.syms: 1422f219e013SMasahiro Yamada return self.syms[name] 1423f219e013SMasahiro Yamada 1424f219e013SMasahiro Yamada new_sym = Symbol() 1425f219e013SMasahiro Yamada new_sym.config = self 1426f219e013SMasahiro Yamada new_sym.name = name 1427f219e013SMasahiro Yamada 1428f219e013SMasahiro Yamada if add_sym_if_not_exists: 1429f219e013SMasahiro Yamada self.syms[name] = new_sym 1430f219e013SMasahiro Yamada else: 1431f219e013SMasahiro Yamada # This warning is generated while evaluating an expression 1432f219e013SMasahiro Yamada # containing undefined symbols using Config.eval() 1433f219e013SMasahiro Yamada self._warn("no symbol {0} in configuration".format(name)) 1434f219e013SMasahiro Yamada 1435f219e013SMasahiro Yamada return new_sym 1436f219e013SMasahiro Yamada 1437f219e013SMasahiro Yamada # 1438f219e013SMasahiro Yamada # Evaluation of symbols and expressions 1439f219e013SMasahiro Yamada # 1440f219e013SMasahiro Yamada 1441f219e013SMasahiro Yamada def _eval_expr(self, expr): 1442f219e013SMasahiro Yamada """Evaluates an expression and returns one of the tristate values "n", 1443f219e013SMasahiro Yamada "m" or "y".""" 1444f219e013SMasahiro Yamada res = self._eval_expr_2(expr) 1445f219e013SMasahiro Yamada 1446f219e013SMasahiro Yamada # Promote "m" to "y" if we're running without modules. Internally, "m" 1447f219e013SMasahiro Yamada # is often rewritten to "m" && MODULES by both the C implementation and 1448f219e013SMasahiro Yamada # kconfiglib, which takes care of cases where "m" should be false if 1449f219e013SMasahiro Yamada # we're running without modules. 1450f219e013SMasahiro Yamada if res == "m" and not self._has_modules(): 1451f219e013SMasahiro Yamada return "y" 1452f219e013SMasahiro Yamada 1453f219e013SMasahiro Yamada return res 1454f219e013SMasahiro Yamada 1455f219e013SMasahiro Yamada def _eval_expr_2(self, expr): 1456f219e013SMasahiro Yamada if expr is None: 1457f219e013SMasahiro Yamada return "y" 1458f219e013SMasahiro Yamada 1459f219e013SMasahiro Yamada if isinstance(expr, Symbol): 1460f219e013SMasahiro Yamada # Non-bool/tristate symbols are always "n" in a tristate sense, 1461f219e013SMasahiro Yamada # regardless of their value 1462f219e013SMasahiro Yamada if expr.type != BOOL and expr.type != TRISTATE: 1463f219e013SMasahiro Yamada return "n" 1464f219e013SMasahiro Yamada return expr.get_value() 1465f219e013SMasahiro Yamada 1466f219e013SMasahiro Yamada if isinstance(expr, str): 1467f219e013SMasahiro Yamada return expr if (expr == "y" or expr == "m") else "n" 1468f219e013SMasahiro Yamada 1469f219e013SMasahiro Yamada first_expr = expr[0] 1470f219e013SMasahiro Yamada 1471f219e013SMasahiro Yamada if first_expr == OR: 1472f219e013SMasahiro Yamada res = "n" 1473f219e013SMasahiro Yamada 1474f219e013SMasahiro Yamada for subexpr in expr[1]: 1475f219e013SMasahiro Yamada ev = self._eval_expr_2(subexpr) 1476f219e013SMasahiro Yamada 1477f219e013SMasahiro Yamada # Return immediately upon discovering a "y" term 1478f219e013SMasahiro Yamada if ev == "y": 1479f219e013SMasahiro Yamada return "y" 1480f219e013SMasahiro Yamada 1481f219e013SMasahiro Yamada if ev == "m": 1482f219e013SMasahiro Yamada res = "m" 1483f219e013SMasahiro Yamada 1484f219e013SMasahiro Yamada # 'res' is either "n" or "m" here; we already handled the 1485f219e013SMasahiro Yamada # short-circuiting "y" case in the loop. 1486f219e013SMasahiro Yamada return res 1487f219e013SMasahiro Yamada 1488f219e013SMasahiro Yamada if first_expr == AND: 1489f219e013SMasahiro Yamada res = "y" 1490f219e013SMasahiro Yamada 1491f219e013SMasahiro Yamada for subexpr in expr[1]: 1492f219e013SMasahiro Yamada ev = self._eval_expr_2(subexpr) 1493f219e013SMasahiro Yamada 1494f219e013SMasahiro Yamada # Return immediately upon discovering an "n" term 1495f219e013SMasahiro Yamada if ev == "n": 1496f219e013SMasahiro Yamada return "n" 1497f219e013SMasahiro Yamada 1498f219e013SMasahiro Yamada if ev == "m": 1499f219e013SMasahiro Yamada res = "m" 1500f219e013SMasahiro Yamada 1501f219e013SMasahiro Yamada # 'res' is either "m" or "y" here; we already handled the 1502f219e013SMasahiro Yamada # short-circuiting "n" case in the loop. 1503f219e013SMasahiro Yamada return res 1504f219e013SMasahiro Yamada 1505f219e013SMasahiro Yamada if first_expr == NOT: 1506f219e013SMasahiro Yamada ev = self._eval_expr_2(expr[1]) 1507f219e013SMasahiro Yamada 1508f219e013SMasahiro Yamada if ev == "y": 1509f219e013SMasahiro Yamada return "n" 1510f219e013SMasahiro Yamada 1511f219e013SMasahiro Yamada return "y" if (ev == "n") else "m" 1512f219e013SMasahiro Yamada 1513f219e013SMasahiro Yamada if first_expr == EQUAL: 1514f219e013SMasahiro Yamada return "y" if (self._get_str_value(expr[1]) == 1515f219e013SMasahiro Yamada self._get_str_value(expr[2])) else "n" 1516f219e013SMasahiro Yamada 1517f219e013SMasahiro Yamada if first_expr == UNEQUAL: 1518f219e013SMasahiro Yamada return "y" if (self._get_str_value(expr[1]) != 1519f219e013SMasahiro Yamada self._get_str_value(expr[2])) else "n" 1520f219e013SMasahiro Yamada 1521f219e013SMasahiro Yamada _internal_error("Internal error while evaluating expression: " 1522f219e013SMasahiro Yamada "unknown operation {0}.".format(first_expr)) 1523f219e013SMasahiro Yamada 1524f219e013SMasahiro Yamada def _get_str_value(self, obj): 1525f219e013SMasahiro Yamada if isinstance(obj, str): 1526f219e013SMasahiro Yamada return obj 1527f219e013SMasahiro Yamada # obj is a Symbol 1528f219e013SMasahiro Yamada return obj.get_value() 1529f219e013SMasahiro Yamada 1530f219e013SMasahiro Yamada def _eval_min(self, e1, e2): 1531f219e013SMasahiro Yamada e1_eval = self._eval_expr(e1) 1532f219e013SMasahiro Yamada e2_eval = self._eval_expr(e2) 1533f219e013SMasahiro Yamada 1534f219e013SMasahiro Yamada return e1_eval if tri_less(e1_eval, e2_eval) else e2_eval 1535f219e013SMasahiro Yamada 1536f219e013SMasahiro Yamada def _eval_max(self, e1, e2): 1537f219e013SMasahiro Yamada e1_eval = self._eval_expr(e1) 1538f219e013SMasahiro Yamada e2_eval = self._eval_expr(e2) 1539f219e013SMasahiro Yamada 1540f219e013SMasahiro Yamada return e1_eval if tri_greater(e1_eval, e2_eval) else e2_eval 1541f219e013SMasahiro Yamada 1542f219e013SMasahiro Yamada # 1543f219e013SMasahiro Yamada # Methods related to the MODULES symbol 1544f219e013SMasahiro Yamada # 1545f219e013SMasahiro Yamada 1546f219e013SMasahiro Yamada def _has_modules(self): 1547f219e013SMasahiro Yamada modules_sym = self.syms.get("MODULES") 1548f219e013SMasahiro Yamada return (modules_sym is not None) and (modules_sym.get_value() == "y") 1549f219e013SMasahiro Yamada 1550f219e013SMasahiro Yamada # 1551f219e013SMasahiro Yamada # Dependency tracking 1552f219e013SMasahiro Yamada # 1553f219e013SMasahiro Yamada 1554f219e013SMasahiro Yamada def _build_dep(self): 1555f219e013SMasahiro Yamada """Populates the Symbol.dep sets, linking the symbol to the symbols 1556f219e013SMasahiro Yamada that immediately depend on it in the sense that changing the value of 1557f219e013SMasahiro Yamada the symbol might affect the values of those other symbols. This is used 1558f219e013SMasahiro Yamada for caching/invalidation purposes. The calculated sets might be larger 1559f219e013SMasahiro Yamada than necessary as we don't do any complicated analysis of the 1560f219e013SMasahiro Yamada expressions.""" 1561f219e013SMasahiro Yamada for sym in self.syms.itervalues(): 1562f219e013SMasahiro Yamada sym.dep = set() 1563f219e013SMasahiro Yamada 1564f219e013SMasahiro Yamada # Adds 'sym' as a directly dependent symbol to all symbols that appear 1565f219e013SMasahiro Yamada # in the expression 'e' 1566f219e013SMasahiro Yamada def add_expr_deps(e, sym): 1567f219e013SMasahiro Yamada for s in _get_expr_syms(e): 1568f219e013SMasahiro Yamada s.dep.add(sym) 1569f219e013SMasahiro Yamada 1570f219e013SMasahiro Yamada # The directly dependent symbols of a symbol are: 1571f219e013SMasahiro Yamada # - Any symbols whose prompts, default values, rev_dep (select 1572f219e013SMasahiro Yamada # condition), or ranges depend on the symbol 1573f219e013SMasahiro Yamada # - Any symbols that belong to the same choice statement as the symbol 1574f219e013SMasahiro Yamada # (these won't be included in 'dep' as that makes the dependency 1575f219e013SMasahiro Yamada # graph unwieldy, but Symbol._get_dependent() will include them) 1576f219e013SMasahiro Yamada # - Any symbols in a choice statement that depends on the symbol 1577f219e013SMasahiro Yamada for sym in self.syms.itervalues(): 1578f219e013SMasahiro Yamada for (_, e) in sym.prompts: 1579f219e013SMasahiro Yamada add_expr_deps(e, sym) 1580f219e013SMasahiro Yamada 1581f219e013SMasahiro Yamada for (v, e) in sym.def_exprs: 1582f219e013SMasahiro Yamada add_expr_deps(v, sym) 1583f219e013SMasahiro Yamada add_expr_deps(e, sym) 1584f219e013SMasahiro Yamada 1585f219e013SMasahiro Yamada add_expr_deps(sym.rev_dep, sym) 1586f219e013SMasahiro Yamada 1587f219e013SMasahiro Yamada for (l, u, e) in sym.ranges: 1588f219e013SMasahiro Yamada add_expr_deps(l, sym) 1589f219e013SMasahiro Yamada add_expr_deps(u, sym) 1590f219e013SMasahiro Yamada add_expr_deps(e, sym) 1591f219e013SMasahiro Yamada 1592f219e013SMasahiro Yamada if sym.is_choice_symbol_: 1593f219e013SMasahiro Yamada choice = sym.parent 1594f219e013SMasahiro Yamada 1595f219e013SMasahiro Yamada for (_, e) in choice.prompts: 1596f219e013SMasahiro Yamada add_expr_deps(e, sym) 1597f219e013SMasahiro Yamada 1598f219e013SMasahiro Yamada for (_, e) in choice.def_exprs: 1599f219e013SMasahiro Yamada add_expr_deps(e, sym) 1600f219e013SMasahiro Yamada 1601f219e013SMasahiro Yamada def _expr_val_str(self, expr, no_value_str = "(none)", get_val_instead_of_eval = False): 1602f219e013SMasahiro Yamada # Since values are valid expressions, _expr_to_str() will get a nice 1603f219e013SMasahiro Yamada # string representation for those as well. 1604f219e013SMasahiro Yamada 1605f219e013SMasahiro Yamada if expr is None: 1606f219e013SMasahiro Yamada return no_value_str 1607f219e013SMasahiro Yamada 1608f219e013SMasahiro Yamada if get_val_instead_of_eval: 1609f219e013SMasahiro Yamada if isinstance(expr, str): 1610f219e013SMasahiro Yamada return _expr_to_str(expr) 1611f219e013SMasahiro Yamada val = expr.get_value() 1612f219e013SMasahiro Yamada else: 1613f219e013SMasahiro Yamada val = self._eval_expr(expr) 1614f219e013SMasahiro Yamada 1615f219e013SMasahiro Yamada return "{0} (value: {1})".format(_expr_to_str(expr), _expr_to_str(val)) 1616f219e013SMasahiro Yamada 1617f219e013SMasahiro Yamada def _expand_sym_refs(self, s): 1618f219e013SMasahiro Yamada """Expands $-references to symbols in 's' to symbol values, or to the 1619f219e013SMasahiro Yamada empty string for undefined symbols.""" 1620f219e013SMasahiro Yamada 1621f219e013SMasahiro Yamada while 1: 1622f219e013SMasahiro Yamada sym_ref_re_match = sym_ref_re.search(s) 1623f219e013SMasahiro Yamada if sym_ref_re_match is None: 1624f219e013SMasahiro Yamada return s 1625f219e013SMasahiro Yamada 1626f219e013SMasahiro Yamada sym_name = sym_ref_re_match.group(0)[1:] 1627f219e013SMasahiro Yamada sym = self.syms.get(sym_name) 1628f219e013SMasahiro Yamada expansion = "" if sym is None else sym.get_value() 1629f219e013SMasahiro Yamada 1630f219e013SMasahiro Yamada s = s[:sym_ref_re_match.start()] + \ 1631f219e013SMasahiro Yamada expansion + \ 1632f219e013SMasahiro Yamada s[sym_ref_re_match.end():] 1633f219e013SMasahiro Yamada 1634f219e013SMasahiro Yamada def _get_sym_or_choice_str(self, sc): 1635f219e013SMasahiro Yamada """Symbols and choices have many properties in common, so we factor out 1636f219e013SMasahiro Yamada common __str__() stuff here. "sc" is short for "symbol or choice".""" 1637f219e013SMasahiro Yamada 1638f219e013SMasahiro Yamada # As we deal a lot with string representations here, use some 1639f219e013SMasahiro Yamada # convenient shorthand: 1640f219e013SMasahiro Yamada s = _expr_to_str 1641f219e013SMasahiro Yamada 1642f219e013SMasahiro Yamada # 1643f219e013SMasahiro Yamada # Common symbol/choice properties 1644f219e013SMasahiro Yamada # 1645f219e013SMasahiro Yamada 1646f219e013SMasahiro Yamada user_value_str = "(no user value)" if sc.user_val is None else s(sc.user_val) 1647f219e013SMasahiro Yamada 1648f219e013SMasahiro Yamada visibility_str = s(sc.get_visibility()) 1649f219e013SMasahiro Yamada 1650f219e013SMasahiro Yamada # Build prompts string 1651f219e013SMasahiro Yamada if sc.prompts == []: 1652f219e013SMasahiro Yamada prompts_str = " (no prompts)" 1653f219e013SMasahiro Yamada else: 1654f219e013SMasahiro Yamada prompts_str_rows = [] 1655f219e013SMasahiro Yamada 1656f219e013SMasahiro Yamada for (prompt, cond_expr) in sc.orig_prompts: 1657f219e013SMasahiro Yamada if cond_expr is None: 1658f219e013SMasahiro Yamada prompts_str_rows.append(' "{0}"'.format(prompt)) 1659f219e013SMasahiro Yamada else: 1660f219e013SMasahiro Yamada prompts_str_rows.append(' "{0}" if '.format(prompt) + 1661f219e013SMasahiro Yamada self._expr_val_str(cond_expr)) 1662f219e013SMasahiro Yamada 1663f219e013SMasahiro Yamada prompts_str = "\n".join(prompts_str_rows) 1664f219e013SMasahiro Yamada 1665f219e013SMasahiro Yamada # Build locations string 1666f219e013SMasahiro Yamada if sc.def_locations == []: 1667f219e013SMasahiro Yamada locations_str = "(no locations)" 1668f219e013SMasahiro Yamada else: 1669f219e013SMasahiro Yamada locations_str = " ".join(["{0}:{1}".format(filename, linenr) for 1670f219e013SMasahiro Yamada (filename, linenr) in sc.def_locations]) 1671f219e013SMasahiro Yamada 1672f219e013SMasahiro Yamada # Build additional-dependencies-from-menus-and-if's string 1673f219e013SMasahiro Yamada additional_deps_str = " " + self._expr_val_str(sc.deps_from_containing, 1674f219e013SMasahiro Yamada "(no additional dependencies)") 1675f219e013SMasahiro Yamada 1676f219e013SMasahiro Yamada # 1677f219e013SMasahiro Yamada # Symbol-specific stuff 1678f219e013SMasahiro Yamada # 1679f219e013SMasahiro Yamada 1680f219e013SMasahiro Yamada if isinstance(sc, Symbol): 1681f219e013SMasahiro Yamada 1682f219e013SMasahiro Yamada # Build value string 1683f219e013SMasahiro Yamada value_str = s(sc.get_value()) 1684f219e013SMasahiro Yamada 1685f219e013SMasahiro Yamada # Build ranges string 1686f219e013SMasahiro Yamada if isinstance(sc, Symbol): 1687f219e013SMasahiro Yamada if sc.ranges == []: 1688f219e013SMasahiro Yamada ranges_str = " (no ranges)" 1689f219e013SMasahiro Yamada else: 1690f219e013SMasahiro Yamada ranges_str_rows = [] 1691f219e013SMasahiro Yamada 1692f219e013SMasahiro Yamada for (l, u, cond_expr) in sc.ranges: 1693f219e013SMasahiro Yamada if cond_expr is None: 1694f219e013SMasahiro Yamada ranges_str_rows.append(" [{0}, {1}]".format(s(l), s(u))) 1695f219e013SMasahiro Yamada else: 1696f219e013SMasahiro Yamada ranges_str_rows.append(" [{0}, {1}] if {2}" 1697f219e013SMasahiro Yamada .format(s(l), s(u), self._expr_val_str(cond_expr))) 1698f219e013SMasahiro Yamada 1699f219e013SMasahiro Yamada ranges_str = "\n".join(ranges_str_rows) 1700f219e013SMasahiro Yamada 1701f219e013SMasahiro Yamada # Build default values string 1702f219e013SMasahiro Yamada if sc.def_exprs == []: 1703f219e013SMasahiro Yamada defaults_str = " (no default values)" 1704f219e013SMasahiro Yamada else: 1705f219e013SMasahiro Yamada defaults_str_rows = [] 1706f219e013SMasahiro Yamada 1707f219e013SMasahiro Yamada for (val_expr, cond_expr) in sc.orig_def_exprs: 1708f219e013SMasahiro Yamada row_str = " " + self._expr_val_str(val_expr, "(none)", sc.type == STRING) 1709f219e013SMasahiro Yamada defaults_str_rows.append(row_str) 1710f219e013SMasahiro Yamada defaults_str_rows.append(" Condition: " + self._expr_val_str(cond_expr)) 1711f219e013SMasahiro Yamada 1712f219e013SMasahiro Yamada defaults_str = "\n".join(defaults_str_rows) 1713f219e013SMasahiro Yamada 1714f219e013SMasahiro Yamada # Build selects string 1715f219e013SMasahiro Yamada if sc.orig_selects == []: 1716f219e013SMasahiro Yamada selects_str = " (no selects)" 1717f219e013SMasahiro Yamada else: 1718f219e013SMasahiro Yamada selects_str_rows = [] 1719f219e013SMasahiro Yamada 1720f219e013SMasahiro Yamada for (target, cond_expr) in sc.orig_selects: 1721f219e013SMasahiro Yamada if cond_expr is None: 1722f219e013SMasahiro Yamada selects_str_rows.append(" {0}".format(target.name)) 1723f219e013SMasahiro Yamada else: 1724f219e013SMasahiro Yamada selects_str_rows.append(" {0} if ".format(target.name) + 1725f219e013SMasahiro Yamada self._expr_val_str(cond_expr)) 1726f219e013SMasahiro Yamada 1727f219e013SMasahiro Yamada selects_str = "\n".join(selects_str_rows) 1728f219e013SMasahiro Yamada 1729f219e013SMasahiro Yamada # Build reverse dependencies string 1730f219e013SMasahiro Yamada if sc.rev_dep == "n": 1731f219e013SMasahiro Yamada rev_dep_str = " (no reverse dependencies)" 1732f219e013SMasahiro Yamada else: 1733f219e013SMasahiro Yamada rev_dep_str = " " + self._expr_val_str(sc.rev_dep) 1734f219e013SMasahiro Yamada 1735f219e013SMasahiro Yamada res = _sep_lines("Symbol " + (sc.name if sc.name is not None else "(no name)"), 1736f219e013SMasahiro Yamada "Type : " + typename[sc.type], 1737f219e013SMasahiro Yamada "Value : " + value_str, 1738f219e013SMasahiro Yamada "User value : " + user_value_str, 1739f219e013SMasahiro Yamada "Visibility : " + visibility_str, 1740f219e013SMasahiro Yamada "Is choice item : " + bool_str[sc.is_choice_symbol_], 1741f219e013SMasahiro Yamada "Is defined : " + bool_str[sc.is_defined_], 1742f219e013SMasahiro Yamada "Is from env. : " + bool_str[sc.is_from_env], 1743f219e013SMasahiro Yamada "Is special : " + bool_str[sc.is_special_] + "\n") 1744f219e013SMasahiro Yamada 1745f219e013SMasahiro Yamada if sc.ranges != []: 1746f219e013SMasahiro Yamada res += _sep_lines("Ranges:", 1747f219e013SMasahiro Yamada ranges_str + "\n") 1748f219e013SMasahiro Yamada 1749f219e013SMasahiro Yamada res += _sep_lines("Prompts:", 1750f219e013SMasahiro Yamada prompts_str, 1751f219e013SMasahiro Yamada "Default values:", 1752f219e013SMasahiro Yamada defaults_str, 1753f219e013SMasahiro Yamada "Selects:", 1754f219e013SMasahiro Yamada selects_str, 1755f219e013SMasahiro Yamada "Reverse dependencies:", 1756f219e013SMasahiro Yamada rev_dep_str, 1757f219e013SMasahiro Yamada "Additional dependencies from enclosing menus and if's:", 1758f219e013SMasahiro Yamada additional_deps_str, 1759f219e013SMasahiro Yamada "Locations: " + locations_str) 1760f219e013SMasahiro Yamada 1761f219e013SMasahiro Yamada return res 1762f219e013SMasahiro Yamada 1763f219e013SMasahiro Yamada # 1764f219e013SMasahiro Yamada # Choice-specific stuff 1765f219e013SMasahiro Yamada # 1766f219e013SMasahiro Yamada 1767f219e013SMasahiro Yamada # Build name string (for named choices) 1768f219e013SMasahiro Yamada if sc.name is None: 1769f219e013SMasahiro Yamada name_str = "(no name)" 1770f219e013SMasahiro Yamada else: 1771f219e013SMasahiro Yamada name_str = sc.name 1772f219e013SMasahiro Yamada 1773f219e013SMasahiro Yamada # Build selected symbol string 1774f219e013SMasahiro Yamada sel = sc.get_selection() 1775f219e013SMasahiro Yamada if sel is None: 1776f219e013SMasahiro Yamada sel_str = "(no selection)" 1777f219e013SMasahiro Yamada else: 1778f219e013SMasahiro Yamada sel_str = sel.name 1779f219e013SMasahiro Yamada 1780f219e013SMasahiro Yamada # Build mode string 1781f219e013SMasahiro Yamada mode_str = s(sc.get_mode()) 1782f219e013SMasahiro Yamada 1783f219e013SMasahiro Yamada # Build default values string 1784f219e013SMasahiro Yamada if sc.def_exprs == []: 1785f219e013SMasahiro Yamada defaults_str = " (no default values)" 1786f219e013SMasahiro Yamada else: 1787f219e013SMasahiro Yamada defaults_str_rows = [] 1788f219e013SMasahiro Yamada 1789f219e013SMasahiro Yamada for (sym, cond_expr) in sc.orig_def_exprs: 1790f219e013SMasahiro Yamada if cond_expr is None: 1791f219e013SMasahiro Yamada defaults_str_rows.append(" {0}".format(sym.name)) 1792f219e013SMasahiro Yamada else: 1793f219e013SMasahiro Yamada defaults_str_rows.append(" {0} if ".format(sym.name) + 1794f219e013SMasahiro Yamada self._expr_val_str(cond_expr)) 1795f219e013SMasahiro Yamada 1796f219e013SMasahiro Yamada defaults_str = "\n".join(defaults_str_rows) 1797f219e013SMasahiro Yamada 1798f219e013SMasahiro Yamada # Build contained symbols string 1799f219e013SMasahiro Yamada names = [sym.name for sym in sc.get_symbols()] 1800f219e013SMasahiro Yamada 1801f219e013SMasahiro Yamada if names == []: 1802f219e013SMasahiro Yamada syms_string = "(empty)" 1803f219e013SMasahiro Yamada else: 1804f219e013SMasahiro Yamada syms_string = " ".join(names) 1805f219e013SMasahiro Yamada 1806f219e013SMasahiro Yamada return _sep_lines("Choice", 1807f219e013SMasahiro Yamada "Name (for named choices): " + name_str, 1808f219e013SMasahiro Yamada "Type : " + typename[sc.type], 1809f219e013SMasahiro Yamada "Selected symbol : " + sel_str, 1810f219e013SMasahiro Yamada "User value : " + user_value_str, 1811f219e013SMasahiro Yamada "Mode : " + mode_str, 1812f219e013SMasahiro Yamada "Visibility : " + visibility_str, 1813f219e013SMasahiro Yamada "Optional : " + bool_str[sc.optional], 1814f219e013SMasahiro Yamada "Prompts:", 1815f219e013SMasahiro Yamada prompts_str, 1816f219e013SMasahiro Yamada "Defaults:", 1817f219e013SMasahiro Yamada defaults_str, 1818f219e013SMasahiro Yamada "Choice symbols:", 1819f219e013SMasahiro Yamada " " + syms_string, 1820f219e013SMasahiro Yamada "Additional dependencies from enclosing menus and if's:", 1821f219e013SMasahiro Yamada additional_deps_str, 1822f219e013SMasahiro Yamada "Locations: " + locations_str) 1823f219e013SMasahiro Yamada 1824f219e013SMasahiro Yamada def _expr_depends_on(self, expr, sym): 1825f219e013SMasahiro Yamada """Reimplementation of expr_depends_symbol() from mconf.c. Used to 1826f219e013SMasahiro Yamada determine if a submenu should be implicitly created, which influences what 1827f219e013SMasahiro Yamada items inside choice statements are considered choice items.""" 1828f219e013SMasahiro Yamada if expr is None: 1829f219e013SMasahiro Yamada return False 1830f219e013SMasahiro Yamada 1831f219e013SMasahiro Yamada def rec(expr): 1832f219e013SMasahiro Yamada if isinstance(expr, str): 1833f219e013SMasahiro Yamada return False 1834f219e013SMasahiro Yamada 1835f219e013SMasahiro Yamada if isinstance(expr, Symbol): 1836f219e013SMasahiro Yamada return expr is sym 1837f219e013SMasahiro Yamada 1838f219e013SMasahiro Yamada e0 = expr[0] 1839f219e013SMasahiro Yamada 1840f219e013SMasahiro Yamada if e0 == EQUAL or e0 == UNEQUAL: 1841f219e013SMasahiro Yamada return self._eq_to_sym(expr) is sym 1842f219e013SMasahiro Yamada 1843f219e013SMasahiro Yamada if e0 == AND: 1844f219e013SMasahiro Yamada for and_expr in expr[1]: 1845f219e013SMasahiro Yamada if rec(and_expr): 1846f219e013SMasahiro Yamada return True 1847f219e013SMasahiro Yamada 1848f219e013SMasahiro Yamada return False 1849f219e013SMasahiro Yamada 1850f219e013SMasahiro Yamada return rec(expr) 1851f219e013SMasahiro Yamada 1852f219e013SMasahiro Yamada def _eq_to_sym(self, eq): 1853f219e013SMasahiro Yamada """_expr_depends_on() helper. For (in)equalities of the form sym = y/m 1854f219e013SMasahiro Yamada or sym != n, returns sym. For other (in)equalities, returns None.""" 1855f219e013SMasahiro Yamada relation, left, right = eq 1856f219e013SMasahiro Yamada 1857f219e013SMasahiro Yamada left = self._transform_n_m_y(left) 1858f219e013SMasahiro Yamada right = self._transform_n_m_y(right) 1859f219e013SMasahiro Yamada 1860f219e013SMasahiro Yamada # Make sure the symbol (if any) appears to the left 1861f219e013SMasahiro Yamada if not isinstance(left, Symbol): 1862f219e013SMasahiro Yamada left, right = right, left 1863f219e013SMasahiro Yamada 1864f219e013SMasahiro Yamada if not isinstance(left, Symbol): 1865f219e013SMasahiro Yamada return None 1866f219e013SMasahiro Yamada 1867f219e013SMasahiro Yamada if (relation == EQUAL and (right == "m" or right == "y")) or \ 1868f219e013SMasahiro Yamada (relation == UNEQUAL and right == "n"): 1869f219e013SMasahiro Yamada return left 1870f219e013SMasahiro Yamada 1871f219e013SMasahiro Yamada return None 1872f219e013SMasahiro Yamada 1873f219e013SMasahiro Yamada def _transform_n_m_y(self, item): 1874f219e013SMasahiro Yamada """_eq_to_sym() helper. Translates the symbols n, m, and y to their 1875f219e013SMasahiro Yamada string equivalents.""" 1876f219e013SMasahiro Yamada if item is self.n: 1877f219e013SMasahiro Yamada return "n" 1878f219e013SMasahiro Yamada if item is self.m: 1879f219e013SMasahiro Yamada return "m" 1880f219e013SMasahiro Yamada if item is self.y: 1881f219e013SMasahiro Yamada return "y" 1882f219e013SMasahiro Yamada return item 1883f219e013SMasahiro Yamada 1884f219e013SMasahiro Yamada def _warn(self, msg, filename = None, linenr = None): 1885f219e013SMasahiro Yamada """For printing warnings to stderr.""" 1886f219e013SMasahiro Yamada if self.print_warnings: 1887f219e013SMasahiro Yamada self._warn_or_undef_assign(msg, WARNING, filename, linenr) 1888f219e013SMasahiro Yamada 1889f219e013SMasahiro Yamada def _undef_assign(self, msg, filename = None, linenr = None): 1890f219e013SMasahiro Yamada """For printing informational messages related to assignments 1891f219e013SMasahiro Yamada to undefined variables to stderr.""" 1892f219e013SMasahiro Yamada if self.print_undef_assign: 1893f219e013SMasahiro Yamada self._warn_or_undef_assign(msg, UNDEF_ASSIGN, filename, linenr) 1894f219e013SMasahiro Yamada 1895f219e013SMasahiro Yamada def _warn_or_undef_assign(self, msg, msg_type, filename, linenr): 1896f219e013SMasahiro Yamada if filename is not None: 1897f219e013SMasahiro Yamada sys.stderr.write("{0}:".format(_clean_up_path(filename))) 1898f219e013SMasahiro Yamada if linenr is not None: 1899f219e013SMasahiro Yamada sys.stderr.write("{0}:".format(linenr)) 1900f219e013SMasahiro Yamada 1901f219e013SMasahiro Yamada if msg_type == WARNING: 1902f219e013SMasahiro Yamada sys.stderr.write("warning: ") 1903f219e013SMasahiro Yamada elif msg_type == UNDEF_ASSIGN: 1904f219e013SMasahiro Yamada sys.stderr.write("info: ") 1905f219e013SMasahiro Yamada else: 1906f219e013SMasahiro Yamada _internal_error('Internal error while printing warning: unknown warning type "{0}".' 1907f219e013SMasahiro Yamada .format(msg_type)) 1908f219e013SMasahiro Yamada 1909f219e013SMasahiro Yamada sys.stderr.write(msg + "\n") 1910f219e013SMasahiro Yamada 1911f219e013SMasahiro Yamadadef _get_expr_syms(expr): 1912f219e013SMasahiro Yamada """Returns the set() of symbols appearing in expr.""" 1913f219e013SMasahiro Yamada res = set() 1914f219e013SMasahiro Yamada if expr is None: 1915f219e013SMasahiro Yamada return res 1916f219e013SMasahiro Yamada 1917f219e013SMasahiro Yamada def rec(expr): 1918f219e013SMasahiro Yamada if isinstance(expr, Symbol): 1919f219e013SMasahiro Yamada res.add(expr) 1920f219e013SMasahiro Yamada return 1921f219e013SMasahiro Yamada 1922f219e013SMasahiro Yamada if isinstance(expr, str): 1923f219e013SMasahiro Yamada return 1924f219e013SMasahiro Yamada 1925f219e013SMasahiro Yamada e0 = expr[0] 1926f219e013SMasahiro Yamada 1927f219e013SMasahiro Yamada if e0 == OR or e0 == AND: 1928f219e013SMasahiro Yamada for term in expr[1]: 1929f219e013SMasahiro Yamada rec(term) 1930f219e013SMasahiro Yamada 1931f219e013SMasahiro Yamada elif e0 == NOT: 1932f219e013SMasahiro Yamada rec(expr[1]) 1933f219e013SMasahiro Yamada 1934f219e013SMasahiro Yamada elif e0 == EQUAL or e0 == UNEQUAL: 1935f219e013SMasahiro Yamada _, v1, v2 = expr 1936f219e013SMasahiro Yamada 1937f219e013SMasahiro Yamada if isinstance(v1, Symbol): 1938f219e013SMasahiro Yamada res.add(v1) 1939f219e013SMasahiro Yamada 1940f219e013SMasahiro Yamada if isinstance(v2, Symbol): 1941f219e013SMasahiro Yamada res.add(v2) 1942f219e013SMasahiro Yamada 1943f219e013SMasahiro Yamada else: 1944f219e013SMasahiro Yamada _internal_error("Internal error while fetching symbols from an " 1945f219e013SMasahiro Yamada "expression with token stream {0}.".format(expr)) 1946f219e013SMasahiro Yamada 1947f219e013SMasahiro Yamada rec(expr) 1948f219e013SMasahiro Yamada return res 1949f219e013SMasahiro Yamada 1950f219e013SMasahiro Yamada 1951f219e013SMasahiro Yamada# 1952f219e013SMasahiro Yamada# Construction of expressions 1953f219e013SMasahiro Yamada# 1954f219e013SMasahiro Yamada 1955f219e013SMasahiro Yamada# These functions as well as the _eval_min/max() functions above equate 1956f219e013SMasahiro Yamada# None with "y", which is usually what we want, but needs to be kept in 1957f219e013SMasahiro Yamada# mind. 1958f219e013SMasahiro Yamada 1959f219e013SMasahiro Yamadadef _make_or(e1, e2): 1960f219e013SMasahiro Yamada # Perform trivial simplification and avoid None's (which 1961f219e013SMasahiro Yamada # correspond to y's) 1962f219e013SMasahiro Yamada if e1 is None or e2 is None or \ 1963f219e013SMasahiro Yamada e1 == "y" or e2 == "y": 1964f219e013SMasahiro Yamada return "y" 1965f219e013SMasahiro Yamada 1966f219e013SMasahiro Yamada if e1 == "n": 1967f219e013SMasahiro Yamada return e2 1968f219e013SMasahiro Yamada 1969f219e013SMasahiro Yamada if e2 == "n": 1970f219e013SMasahiro Yamada return e1 1971f219e013SMasahiro Yamada 1972f219e013SMasahiro Yamada # Prefer to merge/update argument list if possible instead of creating 1973f219e013SMasahiro Yamada # a new OR node 1974f219e013SMasahiro Yamada 1975f219e013SMasahiro Yamada if isinstance(e1, tuple) and e1[0] == OR: 1976f219e013SMasahiro Yamada if isinstance(e2, tuple) and e2[0] == OR: 1977f219e013SMasahiro Yamada return (OR, e1[1] + e2[1]) 1978f219e013SMasahiro Yamada return (OR, e1[1] + [e2]) 1979f219e013SMasahiro Yamada 1980f219e013SMasahiro Yamada if isinstance(e2, tuple) and e2[0] == OR: 1981f219e013SMasahiro Yamada return (OR, e2[1] + [e1]) 1982f219e013SMasahiro Yamada 1983f219e013SMasahiro Yamada return (OR, [e1, e2]) 1984f219e013SMasahiro Yamada 1985f219e013SMasahiro Yamada# Note: returns None if e1 == e2 == None 1986f219e013SMasahiro Yamada 1987f219e013SMasahiro Yamadadef _make_and(e1, e2): 1988f219e013SMasahiro Yamada if e1 == "n" or e2 == "n": 1989f219e013SMasahiro Yamada return "n" 1990f219e013SMasahiro Yamada 1991f219e013SMasahiro Yamada if e1 is None or e1 == "y": 1992f219e013SMasahiro Yamada return e2 1993f219e013SMasahiro Yamada 1994f219e013SMasahiro Yamada if e2 is None or e2 == "y": 1995f219e013SMasahiro Yamada return e1 1996f219e013SMasahiro Yamada 1997f219e013SMasahiro Yamada # Prefer to merge/update argument list if possible instead of creating 1998f219e013SMasahiro Yamada # a new AND node 1999f219e013SMasahiro Yamada 2000f219e013SMasahiro Yamada if isinstance(e1, tuple) and e1[0] == AND: 2001f219e013SMasahiro Yamada if isinstance(e2, tuple) and e2[0] == AND: 2002f219e013SMasahiro Yamada return (AND, e1[1] + e2[1]) 2003f219e013SMasahiro Yamada return (AND, e1[1] + [e2]) 2004f219e013SMasahiro Yamada 2005f219e013SMasahiro Yamada if isinstance(e2, tuple) and e2[0] == AND: 2006f219e013SMasahiro Yamada return (AND, e2[1] + [e1]) 2007f219e013SMasahiro Yamada 2008f219e013SMasahiro Yamada return (AND, [e1, e2]) 2009f219e013SMasahiro Yamada 2010f219e013SMasahiro Yamada# 2011f219e013SMasahiro Yamada# Constants and functions related to types, parsing, evaluation and printing, 2012f219e013SMasahiro Yamada# put globally to unclutter the Config class a bit. 2013f219e013SMasahiro Yamada# 2014f219e013SMasahiro Yamada 2015f219e013SMasahiro Yamada# Tokens 2016f219e013SMasahiro Yamada(T_OR, T_AND, T_NOT, 2017f219e013SMasahiro Yamada T_OPEN_PAREN, T_CLOSE_PAREN, 2018f219e013SMasahiro Yamada T_EQUAL, T_UNEQUAL, 2019f219e013SMasahiro Yamada T_MAINMENU, T_MENU, T_ENDMENU, 2020f219e013SMasahiro Yamada T_SOURCE, T_CHOICE, T_ENDCHOICE, 2021f219e013SMasahiro Yamada T_COMMENT, T_CONFIG, T_MENUCONFIG, 2022f219e013SMasahiro Yamada T_HELP, T_IF, T_ENDIF, T_DEPENDS, T_ON, 2023f219e013SMasahiro Yamada T_OPTIONAL, T_PROMPT, T_DEFAULT, 2024f219e013SMasahiro Yamada T_BOOL, T_TRISTATE, T_HEX, T_INT, T_STRING, 2025f219e013SMasahiro Yamada T_DEF_BOOL, T_DEF_TRISTATE, 2026f219e013SMasahiro Yamada T_SELECT, T_RANGE, T_OPTION, T_ENV, 2027f219e013SMasahiro Yamada T_DEFCONFIG_LIST, T_MODULES, T_VISIBLE) = range(0, 38) 2028f219e013SMasahiro Yamada 2029f219e013SMasahiro Yamada# Keyword to token map 2030f219e013SMasahiro Yamadakeywords = { 2031f219e013SMasahiro Yamada "mainmenu" : T_MAINMENU, 2032f219e013SMasahiro Yamada "menu" : T_MENU, 2033f219e013SMasahiro Yamada "endmenu" : T_ENDMENU, 2034f219e013SMasahiro Yamada "endif" : T_ENDIF, 2035f219e013SMasahiro Yamada "endchoice" : T_ENDCHOICE, 2036f219e013SMasahiro Yamada "source" : T_SOURCE, 2037f219e013SMasahiro Yamada "choice" : T_CHOICE, 2038f219e013SMasahiro Yamada "config" : T_CONFIG, 2039f219e013SMasahiro Yamada "comment" : T_COMMENT, 2040f219e013SMasahiro Yamada "menuconfig" : T_MENUCONFIG, 2041f219e013SMasahiro Yamada "help" : T_HELP, 2042f219e013SMasahiro Yamada "if" : T_IF, 2043f219e013SMasahiro Yamada "depends" : T_DEPENDS, 2044f219e013SMasahiro Yamada "on" : T_ON, 2045f219e013SMasahiro Yamada "optional" : T_OPTIONAL, 2046f219e013SMasahiro Yamada "prompt" : T_PROMPT, 2047f219e013SMasahiro Yamada "default" : T_DEFAULT, 2048f219e013SMasahiro Yamada "bool" : T_BOOL, 2049f219e013SMasahiro Yamada "boolean" : T_BOOL, 2050f219e013SMasahiro Yamada "tristate" : T_TRISTATE, 2051f219e013SMasahiro Yamada "int" : T_INT, 2052f219e013SMasahiro Yamada "hex" : T_HEX, 2053f219e013SMasahiro Yamada "def_bool" : T_DEF_BOOL, 2054f219e013SMasahiro Yamada "def_tristate" : T_DEF_TRISTATE, 2055f219e013SMasahiro Yamada "string" : T_STRING, 2056f219e013SMasahiro Yamada "select" : T_SELECT, 2057f219e013SMasahiro Yamada "range" : T_RANGE, 2058f219e013SMasahiro Yamada "option" : T_OPTION, 2059f219e013SMasahiro Yamada "env" : T_ENV, 2060f219e013SMasahiro Yamada "defconfig_list" : T_DEFCONFIG_LIST, 2061f219e013SMasahiro Yamada "modules" : T_MODULES, 2062f219e013SMasahiro Yamada "visible" : T_VISIBLE } 2063f219e013SMasahiro Yamada 2064f219e013SMasahiro Yamada# Strings to use for True and False 2065f219e013SMasahiro Yamadabool_str = { False : "false", True : "true" } 2066f219e013SMasahiro Yamada 2067f219e013SMasahiro Yamada# Tokens after which identifier-like lexemes are treated as strings. T_CHOICE 2068f219e013SMasahiro Yamada# is included to avoid symbols being registered for named choices. 2069f219e013SMasahiro Yamadastring_lex = frozenset((T_BOOL, T_TRISTATE, T_INT, T_HEX, T_STRING, T_CHOICE, 2070f219e013SMasahiro Yamada T_PROMPT, T_MENU, T_COMMENT, T_SOURCE, T_MAINMENU)) 2071f219e013SMasahiro Yamada 2072f219e013SMasahiro Yamada# Matches the initial token on a line; see _tokenize(). 2073f219e013SMasahiro Yamadainitial_token_re = re.compile(r"[^\w]*(\w+)") 2074f219e013SMasahiro Yamada 2075f219e013SMasahiro Yamada# Matches an identifier/keyword optionally preceded by whitespace 2076f219e013SMasahiro Yamadaid_keyword_re = re.compile(r"\s*([\w./-]+)") 2077f219e013SMasahiro Yamada 2078f219e013SMasahiro Yamada# Regular expressions for parsing .config files 2079f219e013SMasahiro Yamadaset_re = re.compile(r"CONFIG_(\w+)=(.*)") 2080f219e013SMasahiro Yamadaunset_re = re.compile(r"# CONFIG_(\w+) is not set") 2081f219e013SMasahiro Yamada 2082f219e013SMasahiro Yamada# Regular expression for finding $-references to symbols in strings 2083f219e013SMasahiro Yamadasym_ref_re = re.compile(r"\$[A-Za-z_]+") 2084f219e013SMasahiro Yamada 2085f219e013SMasahiro Yamada# Integers representing symbol types 2086f219e013SMasahiro YamadaUNKNOWN, BOOL, TRISTATE, STRING, HEX, INT = range(0, 6) 2087f219e013SMasahiro Yamada 2088f219e013SMasahiro Yamada# Strings to use for types 2089f219e013SMasahiro Yamadatypename = { 2090f219e013SMasahiro Yamada UNKNOWN : "unknown", 2091f219e013SMasahiro Yamada BOOL : "bool", 2092f219e013SMasahiro Yamada TRISTATE : "tristate", 2093f219e013SMasahiro Yamada STRING : "string", 2094f219e013SMasahiro Yamada HEX : "hex", 2095f219e013SMasahiro Yamada INT : "int" } 2096f219e013SMasahiro Yamada 2097f219e013SMasahiro Yamada# Token to type mapping 2098f219e013SMasahiro Yamadatoken_to_type = { T_BOOL : BOOL, 2099f219e013SMasahiro Yamada T_TRISTATE : TRISTATE, 2100f219e013SMasahiro Yamada T_STRING : STRING, 2101f219e013SMasahiro Yamada T_INT : INT, 2102f219e013SMasahiro Yamada T_HEX : HEX } 2103f219e013SMasahiro Yamada 2104f219e013SMasahiro Yamada# Default values for symbols of different types (the value the symbol gets if 2105f219e013SMasahiro Yamada# it is not assigned a user value and none of its 'default' clauses kick in) 2106f219e013SMasahiro Yamadadefault_value = { BOOL : "n", 2107f219e013SMasahiro Yamada TRISTATE : "n", 2108f219e013SMasahiro Yamada STRING : "", 2109f219e013SMasahiro Yamada INT : "", 2110f219e013SMasahiro Yamada HEX : "" } 2111f219e013SMasahiro Yamada 2112f219e013SMasahiro Yamada# Indicates that no item is selected in a choice statement 2113f219e013SMasahiro YamadaNO_SELECTION = 0 2114f219e013SMasahiro Yamada 2115f219e013SMasahiro Yamada# Integers representing expression types 2116f219e013SMasahiro YamadaOR, AND, NOT, EQUAL, UNEQUAL = range(0, 5) 2117f219e013SMasahiro Yamada 2118f219e013SMasahiro Yamada# Map from tristate values to integers 2119f219e013SMasahiro Yamadatri_to_int = { "n" : 0, "m" : 1, "y" : 2 } 2120f219e013SMasahiro Yamada 2121f219e013SMasahiro Yamada# Printing-related stuff 2122f219e013SMasahiro Yamada 2123f219e013SMasahiro Yamadaop_to_str = { AND : " && ", 2124f219e013SMasahiro Yamada OR : " || ", 2125f219e013SMasahiro Yamada EQUAL : " = ", 2126f219e013SMasahiro Yamada UNEQUAL : " != " } 2127f219e013SMasahiro Yamada 2128f219e013SMasahiro Yamadaprecedence = { OR : 0, AND : 1, NOT : 2 } 2129f219e013SMasahiro Yamada 2130f219e013SMasahiro Yamada# Types of informational messages 2131f219e013SMasahiro YamadaWARNING = 0 2132f219e013SMasahiro YamadaUNDEF_ASSIGN = 1 2133f219e013SMasahiro Yamada 2134f219e013SMasahiro Yamadadef _intersperse(lst, op): 2135f219e013SMasahiro Yamada """_expr_to_str() helper. Gets the string representation of each expression in lst 2136f219e013SMasahiro Yamada and produces a list where op has been inserted between the elements.""" 2137f219e013SMasahiro Yamada if lst == []: 2138f219e013SMasahiro Yamada return "" 2139f219e013SMasahiro Yamada 2140f219e013SMasahiro Yamada res = [] 2141f219e013SMasahiro Yamada 2142f219e013SMasahiro Yamada def handle_sub_expr(expr): 2143f219e013SMasahiro Yamada no_parens = isinstance(expr, (str, Symbol)) or \ 2144f219e013SMasahiro Yamada expr[0] in (EQUAL, UNEQUAL) or \ 2145f219e013SMasahiro Yamada precedence[op] <= precedence[expr[0]] 2146f219e013SMasahiro Yamada if not no_parens: 2147f219e013SMasahiro Yamada res.append("(") 2148f219e013SMasahiro Yamada res.extend(_expr_to_str_rec(expr)) 2149f219e013SMasahiro Yamada if not no_parens: 2150f219e013SMasahiro Yamada res.append(")") 2151f219e013SMasahiro Yamada 2152f219e013SMasahiro Yamada op_str = op_to_str[op] 2153f219e013SMasahiro Yamada 2154f219e013SMasahiro Yamada handle_sub_expr(lst[0]) 2155f219e013SMasahiro Yamada for expr in lst[1:]: 2156f219e013SMasahiro Yamada res.append(op_str) 2157f219e013SMasahiro Yamada handle_sub_expr(expr) 2158f219e013SMasahiro Yamada 2159f219e013SMasahiro Yamada return res 2160f219e013SMasahiro Yamada 2161f219e013SMasahiro Yamadadef _expr_to_str(expr): 2162f219e013SMasahiro Yamada s = "".join(_expr_to_str_rec(expr)) 2163f219e013SMasahiro Yamada return s 2164f219e013SMasahiro Yamada 2165f219e013SMasahiro Yamadadef _sym_str_string(sym_or_str): 2166f219e013SMasahiro Yamada if isinstance(sym_or_str, str): 2167f219e013SMasahiro Yamada return '"{0}"'.format(sym_or_str) 2168f219e013SMasahiro Yamada return sym_or_str.name 2169f219e013SMasahiro Yamada 2170f219e013SMasahiro Yamadadef _expr_to_str_rec(expr): 2171f219e013SMasahiro Yamada if expr is None: 2172f219e013SMasahiro Yamada return [""] 2173f219e013SMasahiro Yamada 2174f219e013SMasahiro Yamada if isinstance(expr, (Symbol, str)): 2175f219e013SMasahiro Yamada return [_sym_str_string(expr)] 2176f219e013SMasahiro Yamada 2177f219e013SMasahiro Yamada e0 = expr[0] 2178f219e013SMasahiro Yamada 2179f219e013SMasahiro Yamada if e0 == OR or e0 == AND: 2180f219e013SMasahiro Yamada return _intersperse(expr[1], expr[0]) 2181f219e013SMasahiro Yamada 2182f219e013SMasahiro Yamada if e0 == NOT: 2183f219e013SMasahiro Yamada need_parens = not isinstance(expr[1], (str, Symbol)) 2184f219e013SMasahiro Yamada 2185f219e013SMasahiro Yamada res = ["!"] 2186f219e013SMasahiro Yamada if need_parens: 2187f219e013SMasahiro Yamada res.append("(") 2188f219e013SMasahiro Yamada res.extend(_expr_to_str_rec(expr[1])) 2189f219e013SMasahiro Yamada if need_parens: 2190f219e013SMasahiro Yamada res.append(")") 2191f219e013SMasahiro Yamada return res 2192f219e013SMasahiro Yamada 2193f219e013SMasahiro Yamada if e0 == EQUAL or e0 == UNEQUAL: 2194f219e013SMasahiro Yamada return [_sym_str_string(expr[1]), 2195f219e013SMasahiro Yamada op_to_str[expr[0]], 2196f219e013SMasahiro Yamada _sym_str_string(expr[2])] 2197f219e013SMasahiro Yamada 2198f219e013SMasahiro Yamadaclass _Block: 2199f219e013SMasahiro Yamada 2200f219e013SMasahiro Yamada """Represents a list of items (symbols, menus, choice statements and 2201f219e013SMasahiro Yamada comments) appearing at the top-level of a file or witin a menu, choice or 2202f219e013SMasahiro Yamada if statement.""" 2203f219e013SMasahiro Yamada 2204f219e013SMasahiro Yamada def __init__(self): 2205f219e013SMasahiro Yamada self.items = [] 2206f219e013SMasahiro Yamada 2207f219e013SMasahiro Yamada def get_items(self): 2208f219e013SMasahiro Yamada return self.items 2209f219e013SMasahiro Yamada 2210f219e013SMasahiro Yamada def add_item(self, item): 2211f219e013SMasahiro Yamada self.items.append(item) 2212f219e013SMasahiro Yamada 2213f219e013SMasahiro Yamada def _make_conf(self): 2214f219e013SMasahiro Yamada # Collect the substrings in a list and later use join() instead of += 2215f219e013SMasahiro Yamada # to build the final .config contents. With older Python versions, this 2216f219e013SMasahiro Yamada # yields linear instead of quadratic complexity. 2217f219e013SMasahiro Yamada strings = [] 2218f219e013SMasahiro Yamada for item in self.items: 2219f219e013SMasahiro Yamada strings.extend(item._make_conf()) 2220f219e013SMasahiro Yamada 2221f219e013SMasahiro Yamada return strings 2222f219e013SMasahiro Yamada 2223f219e013SMasahiro Yamada def add_depend_expr(self, expr): 2224f219e013SMasahiro Yamada for item in self.items: 2225f219e013SMasahiro Yamada item.add_depend_expr(expr) 2226f219e013SMasahiro Yamada 2227f219e013SMasahiro Yamadaclass Item(): 2228f219e013SMasahiro Yamada 2229f219e013SMasahiro Yamada """Base class for symbols and other Kconfig constructs. Subclasses are 2230f219e013SMasahiro Yamada Symbol, Choice, Menu, and Comment.""" 2231f219e013SMasahiro Yamada 2232f219e013SMasahiro Yamada def is_symbol(self): 2233f219e013SMasahiro Yamada """Returns True if the item is a symbol, otherwise False. Short for 2234f219e013SMasahiro Yamada isinstance(item, kconfiglib.Symbol).""" 2235f219e013SMasahiro Yamada return isinstance(self, Symbol) 2236f219e013SMasahiro Yamada 2237f219e013SMasahiro Yamada def is_choice(self): 2238f219e013SMasahiro Yamada """Returns True if the item is a choice, otherwise False. Short for 2239f219e013SMasahiro Yamada isinstance(item, kconfiglib.Choice).""" 2240f219e013SMasahiro Yamada return isinstance(self, Choice) 2241f219e013SMasahiro Yamada 2242f219e013SMasahiro Yamada def is_menu(self): 2243f219e013SMasahiro Yamada """Returns True if the item is a menu, otherwise False. Short for 2244f219e013SMasahiro Yamada isinstance(item, kconfiglib.Menu).""" 2245f219e013SMasahiro Yamada return isinstance(self, Menu) 2246f219e013SMasahiro Yamada 2247f219e013SMasahiro Yamada def is_comment(self): 2248f219e013SMasahiro Yamada """Returns True if the item is a comment, otherwise False. Short for 2249f219e013SMasahiro Yamada isinstance(item, kconfiglib.Comment).""" 2250f219e013SMasahiro Yamada return isinstance(self, Comment) 2251f219e013SMasahiro Yamada 2252f219e013SMasahiro Yamadaclass _HasVisibility(): 2253f219e013SMasahiro Yamada 2254f219e013SMasahiro Yamada """Base class for elements that have a "visibility" that acts as an upper 2255f219e013SMasahiro Yamada limit on the values a user can set for them. Subclasses are Symbol and 2256f219e013SMasahiro Yamada Choice (which supply some of the attributes).""" 2257f219e013SMasahiro Yamada 2258f219e013SMasahiro Yamada def __init__(self): 2259f219e013SMasahiro Yamada self.cached_visibility = None 2260f219e013SMasahiro Yamada self.prompts = [] 2261f219e013SMasahiro Yamada 2262f219e013SMasahiro Yamada def _invalidate(self): 2263f219e013SMasahiro Yamada self.cached_visibility = None 2264f219e013SMasahiro Yamada 2265f219e013SMasahiro Yamada def _get_visibility(self): 2266f219e013SMasahiro Yamada if self.cached_visibility is None: 2267f219e013SMasahiro Yamada vis = "n" 2268f219e013SMasahiro Yamada for (prompt, cond_expr) in self.prompts: 2269f219e013SMasahiro Yamada vis = self.config._eval_max(vis, cond_expr) 2270f219e013SMasahiro Yamada 2271f219e013SMasahiro Yamada if isinstance(self, Symbol) and self.is_choice_symbol_: 2272f219e013SMasahiro Yamada vis = self.config._eval_min(vis, self.parent._get_visibility()) 2273f219e013SMasahiro Yamada 2274f219e013SMasahiro Yamada # Promote "m" to "y" if we're dealing with a non-tristate 2275f219e013SMasahiro Yamada if vis == "m" and self.type != TRISTATE: 2276f219e013SMasahiro Yamada vis = "y" 2277f219e013SMasahiro Yamada 2278f219e013SMasahiro Yamada self.cached_visibility = vis 2279f219e013SMasahiro Yamada 2280f219e013SMasahiro Yamada return self.cached_visibility 2281f219e013SMasahiro Yamada 2282f219e013SMasahiro Yamadaclass Symbol(Item, _HasVisibility): 2283f219e013SMasahiro Yamada 2284f219e013SMasahiro Yamada """Represents a configuration symbol - e.g. FOO for 2285f219e013SMasahiro Yamada 2286f219e013SMasahiro Yamada config FOO 2287f219e013SMasahiro Yamada ...""" 2288f219e013SMasahiro Yamada 2289f219e013SMasahiro Yamada # 2290f219e013SMasahiro Yamada # Public interface 2291f219e013SMasahiro Yamada # 2292f219e013SMasahiro Yamada 2293f219e013SMasahiro Yamada def get_value(self): 2294f219e013SMasahiro Yamada """Calculate and return the value of the symbol. See also 2295f219e013SMasahiro Yamada Symbol.set_user_value().""" 2296f219e013SMasahiro Yamada 2297f219e013SMasahiro Yamada if self.cached_value is not None: 2298f219e013SMasahiro Yamada return self.cached_value 2299f219e013SMasahiro Yamada 2300f219e013SMasahiro Yamada self.write_to_conf = False 2301f219e013SMasahiro Yamada 2302f219e013SMasahiro Yamada # As a quirk of Kconfig, undefined symbols get their name as their 2303f219e013SMasahiro Yamada # value. This is why things like "FOO = bar" work for seeing if FOO has 2304f219e013SMasahiro Yamada # the value "bar". 2305f219e013SMasahiro Yamada if self.type == UNKNOWN: 2306f219e013SMasahiro Yamada self.cached_value = self.name 2307f219e013SMasahiro Yamada return self.name 2308f219e013SMasahiro Yamada 2309f219e013SMasahiro Yamada new_val = default_value[self.type] 2310f219e013SMasahiro Yamada 2311f219e013SMasahiro Yamada vis = self._get_visibility() 2312f219e013SMasahiro Yamada 2313f219e013SMasahiro Yamada if self.type == BOOL or self.type == TRISTATE: 2314f219e013SMasahiro Yamada # The visibility and mode (modules-only or single-selection) of 2315f219e013SMasahiro Yamada # choice items will be taken into account in self._get_visibility() 2316f219e013SMasahiro Yamada 2317f219e013SMasahiro Yamada if self.is_choice_symbol_: 2318f219e013SMasahiro Yamada if vis != "n": 2319f219e013SMasahiro Yamada choice = self.parent 2320f219e013SMasahiro Yamada mode = choice.get_mode() 2321f219e013SMasahiro Yamada 2322f219e013SMasahiro Yamada self.write_to_conf = (mode != "n") 2323f219e013SMasahiro Yamada 2324f219e013SMasahiro Yamada if mode == "y": 2325f219e013SMasahiro Yamada new_val = "y" if (choice.get_selection() is self) else "n" 2326f219e013SMasahiro Yamada elif mode == "m": 2327f219e013SMasahiro Yamada if self.user_val == "m" or self.user_val == "y": 2328f219e013SMasahiro Yamada new_val = "m" 2329f219e013SMasahiro Yamada 2330f219e013SMasahiro Yamada else: 2331f219e013SMasahiro Yamada use_defaults = True 2332f219e013SMasahiro Yamada 2333f219e013SMasahiro Yamada if vis != "n": 2334f219e013SMasahiro Yamada # If the symbol is visible and has a user value, use that. 2335f219e013SMasahiro Yamada # Otherwise, look at defaults. 2336f219e013SMasahiro Yamada self.write_to_conf = True 2337f219e013SMasahiro Yamada 2338f219e013SMasahiro Yamada if self.user_val is not None: 2339f219e013SMasahiro Yamada new_val = self.config._eval_min(self.user_val, vis) 2340f219e013SMasahiro Yamada use_defaults = False 2341f219e013SMasahiro Yamada 2342f219e013SMasahiro Yamada if use_defaults: 2343f219e013SMasahiro Yamada for (val_expr, cond_expr) in self.def_exprs: 2344f219e013SMasahiro Yamada cond_eval = self.config._eval_expr(cond_expr) 2345f219e013SMasahiro Yamada 2346f219e013SMasahiro Yamada if cond_eval != "n": 2347f219e013SMasahiro Yamada self.write_to_conf = True 2348f219e013SMasahiro Yamada new_val = self.config._eval_min(val_expr, cond_eval) 2349f219e013SMasahiro Yamada break 2350f219e013SMasahiro Yamada 2351f219e013SMasahiro Yamada # Reverse dependencies take precedence 2352f219e013SMasahiro Yamada rev_dep_val = self.config._eval_expr(self.rev_dep) 2353f219e013SMasahiro Yamada 2354f219e013SMasahiro Yamada if rev_dep_val != "n": 2355f219e013SMasahiro Yamada self.write_to_conf = True 2356f219e013SMasahiro Yamada new_val = self.config._eval_max(new_val, rev_dep_val) 2357f219e013SMasahiro Yamada 2358f219e013SMasahiro Yamada # Promote "m" to "y" for booleans 2359f219e013SMasahiro Yamada if new_val == "m" and self.type == BOOL: 2360f219e013SMasahiro Yamada new_val = "y" 2361f219e013SMasahiro Yamada 2362f219e013SMasahiro Yamada elif self.type == STRING: 2363f219e013SMasahiro Yamada use_defaults = True 2364f219e013SMasahiro Yamada 2365f219e013SMasahiro Yamada if vis != "n": 2366f219e013SMasahiro Yamada self.write_to_conf = True 2367f219e013SMasahiro Yamada if self.user_val is not None: 2368f219e013SMasahiro Yamada new_val = self.user_val 2369f219e013SMasahiro Yamada use_defaults = False 2370f219e013SMasahiro Yamada 2371f219e013SMasahiro Yamada if use_defaults: 2372f219e013SMasahiro Yamada for (val_expr, cond_expr) in self.def_exprs: 2373f219e013SMasahiro Yamada if self.config._eval_expr(cond_expr) != "n": 2374f219e013SMasahiro Yamada self.write_to_conf = True 2375f219e013SMasahiro Yamada new_val = self.config._get_str_value(val_expr) 2376f219e013SMasahiro Yamada break 2377f219e013SMasahiro Yamada 2378f219e013SMasahiro Yamada elif self.type == HEX or self.type == INT: 2379f219e013SMasahiro Yamada has_active_range = False 2380f219e013SMasahiro Yamada low = None 2381f219e013SMasahiro Yamada high = None 2382f219e013SMasahiro Yamada use_defaults = True 2383f219e013SMasahiro Yamada 2384f219e013SMasahiro Yamada base = 16 if self.type == HEX else 10 2385f219e013SMasahiro Yamada 2386f219e013SMasahiro Yamada for(l, h, cond_expr) in self.ranges: 2387f219e013SMasahiro Yamada if self.config._eval_expr(cond_expr) != "n": 2388f219e013SMasahiro Yamada has_active_range = True 2389f219e013SMasahiro Yamada 2390f219e013SMasahiro Yamada low_str = self.config._get_str_value(l) 2391f219e013SMasahiro Yamada high_str = self.config._get_str_value(h) 2392f219e013SMasahiro Yamada 2393f219e013SMasahiro Yamada low = int(low_str, base) if \ 2394f219e013SMasahiro Yamada _is_base_n(low_str, base) else 0 2395f219e013SMasahiro Yamada high = int(high_str, base) if \ 2396f219e013SMasahiro Yamada _is_base_n(high_str, base) else 0 2397f219e013SMasahiro Yamada 2398f219e013SMasahiro Yamada break 2399f219e013SMasahiro Yamada 2400f219e013SMasahiro Yamada if vis != "n": 2401f219e013SMasahiro Yamada self.write_to_conf = True 2402f219e013SMasahiro Yamada 2403f219e013SMasahiro Yamada if self.user_val is not None and \ 2404f219e013SMasahiro Yamada _is_base_n(self.user_val, base) and \ 2405f219e013SMasahiro Yamada (not has_active_range or 2406f219e013SMasahiro Yamada low <= int(self.user_val, base) <= high): 2407f219e013SMasahiro Yamada 2408f219e013SMasahiro Yamada # If the user value is OK, it is stored in exactly the same 2409f219e013SMasahiro Yamada # form as specified in the assignment (with or without 2410f219e013SMasahiro Yamada # "0x", etc). 2411f219e013SMasahiro Yamada 2412f219e013SMasahiro Yamada use_defaults = False 2413f219e013SMasahiro Yamada new_val = self.user_val 2414f219e013SMasahiro Yamada 2415f219e013SMasahiro Yamada if use_defaults: 2416f219e013SMasahiro Yamada for (val_expr, cond_expr) in self.def_exprs: 2417f219e013SMasahiro Yamada if self.config._eval_expr(cond_expr) != "n": 2418f219e013SMasahiro Yamada self.write_to_conf = True 2419f219e013SMasahiro Yamada 2420f219e013SMasahiro Yamada # If the default value is OK, it is stored in exactly 2421f219e013SMasahiro Yamada # the same form as specified. Otherwise, it is clamped 2422f219e013SMasahiro Yamada # to the range, and the output has "0x" as appropriate 2423f219e013SMasahiro Yamada # for the type. 2424f219e013SMasahiro Yamada 2425f219e013SMasahiro Yamada new_val = self.config._get_str_value(val_expr) 2426f219e013SMasahiro Yamada 2427f219e013SMasahiro Yamada if _is_base_n(new_val, base): 2428f219e013SMasahiro Yamada new_val_num = int(new_val, base) 2429f219e013SMasahiro Yamada if has_active_range: 2430f219e013SMasahiro Yamada clamped_val = None 2431f219e013SMasahiro Yamada 2432f219e013SMasahiro Yamada if new_val_num < low: 2433f219e013SMasahiro Yamada clamped_val = low 2434f219e013SMasahiro Yamada elif new_val_num > high: 2435f219e013SMasahiro Yamada clamped_val = high 2436f219e013SMasahiro Yamada 2437f219e013SMasahiro Yamada if clamped_val is not None: 2438f219e013SMasahiro Yamada new_val = (hex(clamped_val) if \ 2439f219e013SMasahiro Yamada self.type == HEX else str(clamped_val)) 2440f219e013SMasahiro Yamada 2441f219e013SMasahiro Yamada break 2442f219e013SMasahiro Yamada else: # For the for loop 2443f219e013SMasahiro Yamada # If no user value or default kicks in but the hex/int has 2444f219e013SMasahiro Yamada # an active range, then the low end of the range is used, 2445f219e013SMasahiro Yamada # provided it's > 0, with "0x" prepended as appropriate. 2446f219e013SMasahiro Yamada 2447f219e013SMasahiro Yamada if has_active_range and low > 0: 2448f219e013SMasahiro Yamada new_val = (hex(low) if self.type == HEX else str(low)) 2449f219e013SMasahiro Yamada 2450f219e013SMasahiro Yamada self.cached_value = new_val 2451f219e013SMasahiro Yamada return new_val 2452f219e013SMasahiro Yamada 2453f219e013SMasahiro Yamada def set_user_value(self, v): 2454f219e013SMasahiro Yamada """Sets the user value of the symbol. 2455f219e013SMasahiro Yamada 2456f219e013SMasahiro Yamada Equal in effect to assigning the value to the symbol within a .config 2457f219e013SMasahiro Yamada file. Use get_lower/upper_bound() or get_assignable_values() to find 2458f219e013SMasahiro Yamada the range of currently assignable values for bool and tristate symbols; 2459f219e013SMasahiro Yamada setting values outside this range will cause the user value to differ 2460f219e013SMasahiro Yamada from the result of Symbol.get_value() (be truncated). Values that are 2461f219e013SMasahiro Yamada invalid for the type (such as a_bool.set_user_value("foo")) are 2462f219e013SMasahiro Yamada ignored, and a warning is emitted if an attempt is made to assign such 2463f219e013SMasahiro Yamada a value. 2464f219e013SMasahiro Yamada 2465f219e013SMasahiro Yamada For any type of symbol, is_modifiable() can be used to check if a user 2466f219e013SMasahiro Yamada value will currently have any effect on the symbol, as determined by 2467f219e013SMasahiro Yamada its visibility and range of assignable values. Any value that is valid 2468f219e013SMasahiro Yamada for the type (bool, tristate, etc.) will end up being reflected in 2469f219e013SMasahiro Yamada get_user_value() though, and might have an effect later if conditions 2470f219e013SMasahiro Yamada change. To get rid of the user value, use unset_user_value(). 2471f219e013SMasahiro Yamada 2472f219e013SMasahiro Yamada Any symbols dependent on the symbol are (recursively) invalidated, so 2473f219e013SMasahiro Yamada things will just work with regards to dependencies. 2474f219e013SMasahiro Yamada 2475f219e013SMasahiro Yamada v -- The user value to give to the symbol.""" 2476f219e013SMasahiro Yamada self._set_user_value_no_invalidate(v, False) 2477f219e013SMasahiro Yamada 2478f219e013SMasahiro Yamada # There might be something more efficient you could do here, but play 2479f219e013SMasahiro Yamada # it safe. 2480f219e013SMasahiro Yamada if self.name == "MODULES": 2481f219e013SMasahiro Yamada self.config._invalidate_all() 2482f219e013SMasahiro Yamada return 2483f219e013SMasahiro Yamada 2484f219e013SMasahiro Yamada self._invalidate() 2485f219e013SMasahiro Yamada self._invalidate_dependent() 2486f219e013SMasahiro Yamada 2487f219e013SMasahiro Yamada def unset_user_value(self): 2488f219e013SMasahiro Yamada """Resets the user value of the symbol, as if the symbol had never 2489f219e013SMasahiro Yamada gotten a user value via Config.load_config() or 2490f219e013SMasahiro Yamada Symbol.set_user_value().""" 2491f219e013SMasahiro Yamada self._unset_user_value_no_recursive_invalidate() 2492f219e013SMasahiro Yamada self._invalidate_dependent() 2493f219e013SMasahiro Yamada 2494f219e013SMasahiro Yamada def get_user_value(self): 2495f219e013SMasahiro Yamada """Returns the value assigned to the symbol in a .config or via 2496f219e013SMasahiro Yamada Symbol.set_user_value() (provided the value was valid for the type of the 2497f219e013SMasahiro Yamada symbol). Returns None in case of no user value.""" 2498f219e013SMasahiro Yamada return self.user_val 2499f219e013SMasahiro Yamada 2500f219e013SMasahiro Yamada def get_name(self): 2501f219e013SMasahiro Yamada """Returns the name of the symbol.""" 2502f219e013SMasahiro Yamada return self.name 2503f219e013SMasahiro Yamada 2504f219e013SMasahiro Yamada def get_prompts(self): 2505f219e013SMasahiro Yamada """Returns a list of prompts defined for the symbol, in the order they 2506f219e013SMasahiro Yamada appear in the configuration files. Returns the empty list for symbols 2507f219e013SMasahiro Yamada with no prompt. 2508f219e013SMasahiro Yamada 2509f219e013SMasahiro Yamada This list will have a single entry for the vast majority of symbols 2510f219e013SMasahiro Yamada having prompts, but having multiple prompts for a single symbol is 2511f219e013SMasahiro Yamada possible through having multiple 'config' entries for it.""" 2512f219e013SMasahiro Yamada return [prompt for prompt, _ in self.orig_prompts] 2513f219e013SMasahiro Yamada 2514f219e013SMasahiro Yamada def get_upper_bound(self): 2515f219e013SMasahiro Yamada """For string/hex/int symbols and for bool and tristate symbols that 2516f219e013SMasahiro Yamada cannot be modified (see is_modifiable()), returns None. 2517f219e013SMasahiro Yamada 2518f219e013SMasahiro Yamada Otherwise, returns the highest value the symbol can be set to with 2519f219e013SMasahiro Yamada Symbol.set_user_value() (that will not be truncated): one of "m" or "y", 2520f219e013SMasahiro Yamada arranged from lowest to highest. This corresponds to the highest value 2521f219e013SMasahiro Yamada the symbol could be given in e.g. the 'make menuconfig' interface. 2522f219e013SMasahiro Yamada 2523f219e013SMasahiro Yamada See also the tri_less*() and tri_greater*() functions, which could come 2524f219e013SMasahiro Yamada in handy.""" 2525f219e013SMasahiro Yamada if self.type != BOOL and self.type != TRISTATE: 2526f219e013SMasahiro Yamada return None 2527f219e013SMasahiro Yamada rev_dep = self.config._eval_expr(self.rev_dep) 2528f219e013SMasahiro Yamada # A bool selected to "m" gets promoted to "y" 2529f219e013SMasahiro Yamada if self.type == BOOL and rev_dep == "m": 2530f219e013SMasahiro Yamada rev_dep = "y" 2531f219e013SMasahiro Yamada vis = self._get_visibility() 2532f219e013SMasahiro Yamada if (tri_to_int[vis] - tri_to_int[rev_dep]) > 0: 2533f219e013SMasahiro Yamada return vis 2534f219e013SMasahiro Yamada return None 2535f219e013SMasahiro Yamada 2536f219e013SMasahiro Yamada def get_lower_bound(self): 2537f219e013SMasahiro Yamada """For string/hex/int symbols and for bool and tristate symbols that 2538f219e013SMasahiro Yamada cannot be modified (see is_modifiable()), returns None. 2539f219e013SMasahiro Yamada 2540f219e013SMasahiro Yamada Otherwise, returns the lowest value the symbol can be set to with 2541f219e013SMasahiro Yamada Symbol.set_user_value() (that will not be truncated): one of "n" or "m", 2542f219e013SMasahiro Yamada arranged from lowest to highest. This corresponds to the lowest value 2543f219e013SMasahiro Yamada the symbol could be given in e.g. the 'make menuconfig' interface. 2544f219e013SMasahiro Yamada 2545f219e013SMasahiro Yamada See also the tri_less*() and tri_greater*() functions, which could come 2546f219e013SMasahiro Yamada in handy.""" 2547f219e013SMasahiro Yamada if self.type != BOOL and self.type != TRISTATE: 2548f219e013SMasahiro Yamada return None 2549f219e013SMasahiro Yamada rev_dep = self.config._eval_expr(self.rev_dep) 2550f219e013SMasahiro Yamada # A bool selected to "m" gets promoted to "y" 2551f219e013SMasahiro Yamada if self.type == BOOL and rev_dep == "m": 2552f219e013SMasahiro Yamada rev_dep = "y" 2553f219e013SMasahiro Yamada if (tri_to_int[self._get_visibility()] - tri_to_int[rev_dep]) > 0: 2554f219e013SMasahiro Yamada return rev_dep 2555f219e013SMasahiro Yamada return None 2556f219e013SMasahiro Yamada 2557f219e013SMasahiro Yamada def get_assignable_values(self): 2558f219e013SMasahiro Yamada """For string/hex/int symbols and for bool and tristate symbols that 2559f219e013SMasahiro Yamada cannot be modified (see is_modifiable()), returns the empty list. 2560f219e013SMasahiro Yamada 2561f219e013SMasahiro Yamada Otherwise, returns a list containing the user values that can be 2562f219e013SMasahiro Yamada assigned to the symbol (that won't be truncated). Usage example: 2563f219e013SMasahiro Yamada 2564f219e013SMasahiro Yamada if "m" in sym.get_assignable_values(): 2565f219e013SMasahiro Yamada sym.set_user_value("m") 2566f219e013SMasahiro Yamada 2567f219e013SMasahiro Yamada This is basically a more convenient interface to 2568f219e013SMasahiro Yamada get_lower/upper_bound() when wanting to test if a particular tristate 2569f219e013SMasahiro Yamada value can be assigned.""" 2570f219e013SMasahiro Yamada if self.type != BOOL and self.type != TRISTATE: 2571f219e013SMasahiro Yamada return [] 2572f219e013SMasahiro Yamada rev_dep = self.config._eval_expr(self.rev_dep) 2573f219e013SMasahiro Yamada # A bool selected to "m" gets promoted to "y" 2574f219e013SMasahiro Yamada if self.type == BOOL and rev_dep == "m": 2575f219e013SMasahiro Yamada rev_dep = "y" 2576f219e013SMasahiro Yamada res = ["n", "m", "y"][tri_to_int[rev_dep] : 2577f219e013SMasahiro Yamada tri_to_int[self._get_visibility()] + 1] 2578f219e013SMasahiro Yamada return res if len(res) > 1 else [] 2579f219e013SMasahiro Yamada 2580f219e013SMasahiro Yamada def get_type(self): 2581f219e013SMasahiro Yamada """Returns the type of the symbol: one of UNKNOWN, BOOL, TRISTATE, 2582f219e013SMasahiro Yamada STRING, HEX, or INT. These are defined at the top level of the module, 2583f219e013SMasahiro Yamada so you'd do something like 2584f219e013SMasahiro Yamada 2585f219e013SMasahiro Yamada if sym.get_type() == kconfiglib.STRING: 2586f219e013SMasahiro Yamada ...""" 2587f219e013SMasahiro Yamada return self.type 2588f219e013SMasahiro Yamada 2589f219e013SMasahiro Yamada def get_visibility(self): 2590f219e013SMasahiro Yamada """Returns the visibility of the symbol: one of "n", "m" or "y". For 2591f219e013SMasahiro Yamada bool and tristate symbols, this is an upper bound on the value users 2592f219e013SMasahiro Yamada can set for the symbol. For other types of symbols, a visibility of "n" 2593f219e013SMasahiro Yamada means the user value will be ignored. A visibility of "n" corresponds 2594f219e013SMasahiro Yamada to not being visible in the 'make *config' interfaces. 2595f219e013SMasahiro Yamada 2596f219e013SMasahiro Yamada Example (assuming we're running with modules enabled -- i.e., MODULES 2597f219e013SMasahiro Yamada set to 'y'): 2598f219e013SMasahiro Yamada 2599f219e013SMasahiro Yamada # Assume this has been assigned 'n' 2600f219e013SMasahiro Yamada config N_SYM 2601f219e013SMasahiro Yamada tristate "N_SYM" 2602f219e013SMasahiro Yamada 2603f219e013SMasahiro Yamada # Assume this has been assigned 'm' 2604f219e013SMasahiro Yamada config M_SYM 2605f219e013SMasahiro Yamada tristate "M_SYM" 2606f219e013SMasahiro Yamada 2607f219e013SMasahiro Yamada # Has visibility 'n' 2608f219e013SMasahiro Yamada config A 2609f219e013SMasahiro Yamada tristate "A" 2610f219e013SMasahiro Yamada depends on N_SYM 2611f219e013SMasahiro Yamada 2612f219e013SMasahiro Yamada # Has visibility 'm' 2613f219e013SMasahiro Yamada config B 2614f219e013SMasahiro Yamada tristate "B" 2615f219e013SMasahiro Yamada depends on M_SYM 2616f219e013SMasahiro Yamada 2617f219e013SMasahiro Yamada # Has visibility 'y' 2618f219e013SMasahiro Yamada config C 2619f219e013SMasahiro Yamada tristate "C" 2620f219e013SMasahiro Yamada 2621f219e013SMasahiro Yamada # Has no prompt, and hence visibility 'n' 2622f219e013SMasahiro Yamada config D 2623f219e013SMasahiro Yamada tristate 2624f219e013SMasahiro Yamada 2625f219e013SMasahiro Yamada Having visibility be tri-valued ensures that e.g. a symbol cannot be 2626f219e013SMasahiro Yamada set to "y" by the user if it depends on a symbol with value "m", which 2627f219e013SMasahiro Yamada wouldn't be safe. 2628f219e013SMasahiro Yamada 2629f219e013SMasahiro Yamada You should probably look at get_lower/upper_bound(), 2630f219e013SMasahiro Yamada get_assignable_values() and is_modifiable() before using this.""" 2631f219e013SMasahiro Yamada return self._get_visibility() 2632f219e013SMasahiro Yamada 2633f219e013SMasahiro Yamada def get_parent(self): 2634f219e013SMasahiro Yamada """Returns the menu or choice statement that contains the symbol, or 2635f219e013SMasahiro Yamada None if the symbol is at the top level. Note that if statements are 2636f219e013SMasahiro Yamada treated as syntactic and do not have an explicit class 2637f219e013SMasahiro Yamada representation.""" 2638f219e013SMasahiro Yamada return self.parent 2639f219e013SMasahiro Yamada 2640f219e013SMasahiro Yamada def get_referenced_symbols(self, refs_from_enclosing = False): 2641f219e013SMasahiro Yamada """Returns the set() of all symbols referenced by this symbol. For 2642f219e013SMasahiro Yamada example, the symbol defined by 2643f219e013SMasahiro Yamada 2644f219e013SMasahiro Yamada config FOO 2645f219e013SMasahiro Yamada bool 2646f219e013SMasahiro Yamada prompt "foo" if A && B 2647f219e013SMasahiro Yamada default C if D 2648f219e013SMasahiro Yamada depends on E 2649f219e013SMasahiro Yamada select F if G 2650f219e013SMasahiro Yamada 2651f219e013SMasahiro Yamada references the symbols A through G. 2652f219e013SMasahiro Yamada 2653f219e013SMasahiro Yamada refs_from_enclosing (default: False) -- If True, the symbols 2654f219e013SMasahiro Yamada referenced by enclosing menus and if's will be 2655f219e013SMasahiro Yamada included in the result.""" 2656f219e013SMasahiro Yamada return self.all_referenced_syms if refs_from_enclosing else self.referenced_syms 2657f219e013SMasahiro Yamada 2658f219e013SMasahiro Yamada def get_selected_symbols(self): 2659f219e013SMasahiro Yamada """Returns the set() of all symbols X for which this symbol has a 2660f219e013SMasahiro Yamada 'select X' or 'select X if Y' (regardless of whether Y is satisfied or 2661f219e013SMasahiro Yamada not). This is a subset of the symbols returned by 2662f219e013SMasahiro Yamada get_referenced_symbols().""" 2663f219e013SMasahiro Yamada return self.selected_syms 2664f219e013SMasahiro Yamada 2665f219e013SMasahiro Yamada def get_help(self): 2666f219e013SMasahiro Yamada """Returns the help text of the symbol, or None if the symbol has no 2667f219e013SMasahiro Yamada help text.""" 2668f219e013SMasahiro Yamada return self.help 2669f219e013SMasahiro Yamada 2670f219e013SMasahiro Yamada def get_config(self): 2671f219e013SMasahiro Yamada """Returns the Config instance this symbol is from.""" 2672f219e013SMasahiro Yamada return self.config 2673f219e013SMasahiro Yamada 2674f219e013SMasahiro Yamada def get_def_locations(self): 2675f219e013SMasahiro Yamada """Returns a list of (filename, linenr) tuples, where filename (string) 2676f219e013SMasahiro Yamada and linenr (int) represent a location where the symbol is defined. For 2677f219e013SMasahiro Yamada the vast majority of symbols this list will only contain one element. 2678f219e013SMasahiro Yamada For the following Kconfig, FOO would get two entries: the lines marked 2679f219e013SMasahiro Yamada with *. 2680f219e013SMasahiro Yamada 2681f219e013SMasahiro Yamada config FOO * 2682f219e013SMasahiro Yamada bool "foo prompt 1" 2683f219e013SMasahiro Yamada 2684f219e013SMasahiro Yamada config FOO * 2685f219e013SMasahiro Yamada bool "foo prompt 2" 2686f219e013SMasahiro Yamada """ 2687f219e013SMasahiro Yamada return self.def_locations 2688f219e013SMasahiro Yamada 2689f219e013SMasahiro Yamada def get_ref_locations(self): 2690f219e013SMasahiro Yamada """Returns a list of (filename, linenr) tuples, where filename (string) 2691f219e013SMasahiro Yamada and linenr (int) represent a location where the symbol is referenced in 2692f219e013SMasahiro Yamada the configuration. For example, the lines marked by * would be included 2693f219e013SMasahiro Yamada for FOO below: 2694f219e013SMasahiro Yamada 2695f219e013SMasahiro Yamada config A 2696f219e013SMasahiro Yamada bool 2697f219e013SMasahiro Yamada default BAR || FOO * 2698f219e013SMasahiro Yamada 2699f219e013SMasahiro Yamada config B 2700f219e013SMasahiro Yamada tristate 2701f219e013SMasahiro Yamada depends on FOO * 2702f219e013SMasahiro Yamada default m if FOO * 2703f219e013SMasahiro Yamada 2704f219e013SMasahiro Yamada if FOO * 2705f219e013SMasahiro Yamada config A 2706f219e013SMasahiro Yamada bool "A" 2707f219e013SMasahiro Yamada endif 2708f219e013SMasahiro Yamada 2709f219e013SMasahiro Yamada config FOO (definition not included) 2710f219e013SMasahiro Yamada bool 2711f219e013SMasahiro Yamada """ 2712f219e013SMasahiro Yamada return self.ref_locations 2713f219e013SMasahiro Yamada 2714f219e013SMasahiro Yamada def is_modifiable(self): 2715f219e013SMasahiro Yamada """Returns True if the value of the symbol could be modified by calling 2716f219e013SMasahiro Yamada Symbol.set_user_value() and False otherwise. 2717f219e013SMasahiro Yamada 2718f219e013SMasahiro Yamada For bools and tristates, this corresponds to the symbol being visible 2719f219e013SMasahiro Yamada in the 'make menuconfig' interface and not already being pinned to a 2720f219e013SMasahiro Yamada specific value (e.g. because it is selected by another symbol). 2721f219e013SMasahiro Yamada 2722f219e013SMasahiro Yamada For strings and numbers, this corresponds to just being visible. (See 2723f219e013SMasahiro Yamada Symbol.get_visibility().)""" 2724f219e013SMasahiro Yamada if self.is_special_: 2725f219e013SMasahiro Yamada return False 2726f219e013SMasahiro Yamada if self.type == BOOL or self.type == TRISTATE: 2727f219e013SMasahiro Yamada rev_dep = self.config._eval_expr(self.rev_dep) 2728f219e013SMasahiro Yamada # A bool selected to "m" gets promoted to "y" 2729f219e013SMasahiro Yamada if self.type == BOOL and rev_dep == "m": 2730f219e013SMasahiro Yamada rev_dep = "y" 2731f219e013SMasahiro Yamada return (tri_to_int[self._get_visibility()] - 2732f219e013SMasahiro Yamada tri_to_int[rev_dep]) > 0 2733f219e013SMasahiro Yamada return self._get_visibility() != "n" 2734f219e013SMasahiro Yamada 2735f219e013SMasahiro Yamada def is_defined(self): 2736f219e013SMasahiro Yamada """Returns False if the symbol is referred to in the Kconfig but never 2737f219e013SMasahiro Yamada actually defined, otherwise True.""" 2738f219e013SMasahiro Yamada return self.is_defined_ 2739f219e013SMasahiro Yamada 2740f219e013SMasahiro Yamada def is_special(self): 2741f219e013SMasahiro Yamada """Returns True if the symbol is one of the special symbols n, m, y, or 2742f219e013SMasahiro Yamada UNAME_RELEASE, or gets its value from the environment. Otherwise, 2743f219e013SMasahiro Yamada returns False.""" 2744f219e013SMasahiro Yamada return self.is_special_ 2745f219e013SMasahiro Yamada 2746f219e013SMasahiro Yamada def is_from_environment(self): 2747f219e013SMasahiro Yamada """Returns True if the symbol gets its value from the environment. 2748f219e013SMasahiro Yamada Otherwise, returns False.""" 2749f219e013SMasahiro Yamada return self.is_from_env 2750f219e013SMasahiro Yamada 2751f219e013SMasahiro Yamada def has_ranges(self): 2752f219e013SMasahiro Yamada """Returns True if the symbol is of type INT or HEX and has ranges that 2753f219e013SMasahiro Yamada limits what values it can take on, otherwise False.""" 2754f219e013SMasahiro Yamada return self.ranges != [] 2755f219e013SMasahiro Yamada 2756f219e013SMasahiro Yamada def is_choice_symbol(self): 2757f219e013SMasahiro Yamada """Returns True if the symbol is in a choice statement and is an actual 2758f219e013SMasahiro Yamada choice symbol (see Choice.get_symbols()); otherwise, returns 2759f219e013SMasahiro Yamada False.""" 2760f219e013SMasahiro Yamada return self.is_choice_symbol_ 2761f219e013SMasahiro Yamada 2762f219e013SMasahiro Yamada def is_choice_selection(self): 2763f219e013SMasahiro Yamada """Returns True if the symbol is contained in a choice statement and is 2764f219e013SMasahiro Yamada the selected item, otherwise False. Equivalent to 'sym.is_choice_symbol() 2765f219e013SMasahiro Yamada and sym.get_parent().get_selection() is sym'.""" 2766f219e013SMasahiro Yamada return self.is_choice_symbol_ and self.parent.get_selection() is self 2767f219e013SMasahiro Yamada 2768f219e013SMasahiro Yamada def __str__(self): 2769f219e013SMasahiro Yamada """Returns a string containing various information about the symbol.""" 2770f219e013SMasahiro Yamada return self.config._get_sym_or_choice_str(self) 2771f219e013SMasahiro Yamada 2772f219e013SMasahiro Yamada # 2773f219e013SMasahiro Yamada # Private methods 2774f219e013SMasahiro Yamada # 2775f219e013SMasahiro Yamada 2776f219e013SMasahiro Yamada def __init__(self): 2777f219e013SMasahiro Yamada """Symbol constructor -- not intended to be called directly by 2778f219e013SMasahiro Yamada kconfiglib clients.""" 2779f219e013SMasahiro Yamada 2780f219e013SMasahiro Yamada # Set default values 2781f219e013SMasahiro Yamada _HasVisibility.__init__(self) 2782f219e013SMasahiro Yamada 2783f219e013SMasahiro Yamada self.config = None 2784f219e013SMasahiro Yamada 2785f219e013SMasahiro Yamada self.parent = None 2786f219e013SMasahiro Yamada self.name = None 2787f219e013SMasahiro Yamada self.type = UNKNOWN 2788f219e013SMasahiro Yamada 2789f219e013SMasahiro Yamada self.def_exprs = [] 2790f219e013SMasahiro Yamada self.ranges = [] 2791f219e013SMasahiro Yamada self.rev_dep = "n" 2792f219e013SMasahiro Yamada 2793f219e013SMasahiro Yamada # The prompt, default value and select conditions without any 2794f219e013SMasahiro Yamada # dependencies from menus or if's propagated to them 2795f219e013SMasahiro Yamada 2796f219e013SMasahiro Yamada self.orig_prompts = [] 2797f219e013SMasahiro Yamada self.orig_def_exprs = [] 2798f219e013SMasahiro Yamada self.orig_selects = [] 2799f219e013SMasahiro Yamada 2800f219e013SMasahiro Yamada # Dependencies inherited from containing menus and if's 2801f219e013SMasahiro Yamada self.deps_from_containing = None 2802f219e013SMasahiro Yamada 2803f219e013SMasahiro Yamada self.help = None 2804f219e013SMasahiro Yamada 2805f219e013SMasahiro Yamada # The set of symbols referenced by this symbol (see 2806f219e013SMasahiro Yamada # get_referenced_symbols()) 2807f219e013SMasahiro Yamada self.referenced_syms = set() 2808f219e013SMasahiro Yamada 2809f219e013SMasahiro Yamada # The set of symbols selected by this symbol (see 2810f219e013SMasahiro Yamada # get_selected_symbols()) 2811f219e013SMasahiro Yamada self.selected_syms = set() 2812f219e013SMasahiro Yamada 2813f219e013SMasahiro Yamada # Like 'referenced_syms', but includes symbols from 2814f219e013SMasahiro Yamada # dependencies inherited from enclosing menus and if's 2815f219e013SMasahiro Yamada self.all_referenced_syms = set() 2816f219e013SMasahiro Yamada 2817f219e013SMasahiro Yamada # This is set to True for "actual" choice symbols. See 2818f219e013SMasahiro Yamada # Choice._determine_actual_symbols(). The trailing underscore avoids a 2819f219e013SMasahiro Yamada # collision with is_choice_symbol(). 2820f219e013SMasahiro Yamada self.is_choice_symbol_ = False 2821f219e013SMasahiro Yamada 2822f219e013SMasahiro Yamada # This records only dependencies specified with 'depends on'. Needed 2823f219e013SMasahiro Yamada # when determining actual choice items (hrrrr...). See also 2824f219e013SMasahiro Yamada # Choice._determine_actual_symbols(). 2825f219e013SMasahiro Yamada self.menu_dep = None 2826f219e013SMasahiro Yamada 2827f219e013SMasahiro Yamada # See Symbol.get_ref/def_locations(). 2828f219e013SMasahiro Yamada self.def_locations = [] 2829f219e013SMasahiro Yamada self.ref_locations = [] 2830f219e013SMasahiro Yamada 2831f219e013SMasahiro Yamada self.user_val = None 2832f219e013SMasahiro Yamada 2833f219e013SMasahiro Yamada # Flags 2834f219e013SMasahiro Yamada 2835f219e013SMasahiro Yamada # Should the symbol get an entry in .config? 2836f219e013SMasahiro Yamada self.write_to_conf = False 2837f219e013SMasahiro Yamada 2838f219e013SMasahiro Yamada # Caches the calculated value 2839f219e013SMasahiro Yamada self.cached_value = None 2840f219e013SMasahiro Yamada 2841f219e013SMasahiro Yamada # Note: An instance variable 'self.dep' gets set on the Symbol in 2842f219e013SMasahiro Yamada # Config._build_dep(), linking the symbol to the symbols that 2843f219e013SMasahiro Yamada # immediately depend on it (in a caching/invalidation sense). The total 2844f219e013SMasahiro Yamada # set of dependent symbols for the symbol (the transitive closure) is 2845f219e013SMasahiro Yamada # calculated on an as-needed basis in _get_dependent(). 2846f219e013SMasahiro Yamada 2847f219e013SMasahiro Yamada # Caches the total list of dependent symbols. Calculated in 2848f219e013SMasahiro Yamada # _get_dependent(). 2849f219e013SMasahiro Yamada self.cached_deps = None 2850f219e013SMasahiro Yamada 2851f219e013SMasahiro Yamada # Does the symbol have an entry in the Kconfig file? The trailing 2852f219e013SMasahiro Yamada # underscore avoids a collision with is_defined(). 2853f219e013SMasahiro Yamada self.is_defined_ = False 2854f219e013SMasahiro Yamada 2855f219e013SMasahiro Yamada # Does the symbol get its value in some special way, e.g. from the 2856f219e013SMasahiro Yamada # environment or by being one of the special symbols n, m, and y? If 2857f219e013SMasahiro Yamada # so, the value is stored in self.cached_value, which is never 2858f219e013SMasahiro Yamada # invalidated. The trailing underscore avoids a collision with 2859f219e013SMasahiro Yamada # is_special(). 2860f219e013SMasahiro Yamada self.is_special_ = False 2861f219e013SMasahiro Yamada 2862f219e013SMasahiro Yamada # Does the symbol get its value from the environment? 2863f219e013SMasahiro Yamada self.is_from_env = False 2864f219e013SMasahiro Yamada 2865f219e013SMasahiro Yamada def _invalidate(self): 2866f219e013SMasahiro Yamada if self.is_special_: 2867f219e013SMasahiro Yamada return 2868f219e013SMasahiro Yamada 2869f219e013SMasahiro Yamada if self.is_choice_symbol_: 2870f219e013SMasahiro Yamada self.parent._invalidate() 2871f219e013SMasahiro Yamada 2872f219e013SMasahiro Yamada _HasVisibility._invalidate(self) 2873f219e013SMasahiro Yamada 2874f219e013SMasahiro Yamada self.write_to_conf = False 2875f219e013SMasahiro Yamada self.cached_value = None 2876f219e013SMasahiro Yamada 2877f219e013SMasahiro Yamada def _invalidate_dependent(self): 2878f219e013SMasahiro Yamada for sym in self._get_dependent(): 2879f219e013SMasahiro Yamada sym._invalidate() 2880f219e013SMasahiro Yamada 2881f219e013SMasahiro Yamada def _set_user_value_no_invalidate(self, v, suppress_load_warnings): 2882f219e013SMasahiro Yamada """Like set_user_value(), but does not invalidate any symbols. 2883f219e013SMasahiro Yamada 2884f219e013SMasahiro Yamada suppress_load_warnings -- 2885f219e013SMasahiro Yamada some warnings are annoying when loading a .config that can be helpful 2886f219e013SMasahiro Yamada when manually invoking set_user_value(). This flag is set to True to 2887f219e013SMasahiro Yamada suppress such warnings. 2888f219e013SMasahiro Yamada 2889f219e013SMasahiro Yamada Perhaps this could be made optional for load_config() instead.""" 2890f219e013SMasahiro Yamada 2891f219e013SMasahiro Yamada if self.is_special_: 2892f219e013SMasahiro Yamada if self.is_from_env: 2893f219e013SMasahiro Yamada self.config._warn('attempt to assign the value "{0}" to the ' 2894f219e013SMasahiro Yamada 'symbol {1}, which gets its value from the ' 2895f219e013SMasahiro Yamada 'environment. Assignment ignored.' 2896f219e013SMasahiro Yamada .format(v, self.name)) 2897f219e013SMasahiro Yamada else: 2898f219e013SMasahiro Yamada self.config._warn('attempt to assign the value "{0}" to the ' 2899f219e013SMasahiro Yamada 'special symbol {1}. Assignment ignored.' 2900f219e013SMasahiro Yamada .format(v, self.name)) 2901f219e013SMasahiro Yamada 2902f219e013SMasahiro Yamada return 2903f219e013SMasahiro Yamada 2904f219e013SMasahiro Yamada 2905f219e013SMasahiro Yamada if not self.is_defined_: 2906f219e013SMasahiro Yamada filename, linenr = self.ref_locations[0] 2907f219e013SMasahiro Yamada 2908f219e013SMasahiro Yamada self.config._undef_assign('attempt to assign the value "{0}" to {1}, ' 2909f219e013SMasahiro Yamada "which is referenced at {2}:{3} but never " 2910f219e013SMasahiro Yamada "defined. Assignment ignored." 2911f219e013SMasahiro Yamada .format(v, self.name, filename, linenr)) 2912f219e013SMasahiro Yamada return 2913f219e013SMasahiro Yamada 2914f219e013SMasahiro Yamada # Check if the value is valid for our type 2915f219e013SMasahiro Yamada 2916f219e013SMasahiro Yamada if not (( self.type == BOOL and (v == "n" or v == "y") ) or 2917f219e013SMasahiro Yamada ( self.type == TRISTATE and (v == "n" or v == "m" or 2918f219e013SMasahiro Yamada v == "y") ) or 2919f219e013SMasahiro Yamada ( self.type == STRING ) or 2920f219e013SMasahiro Yamada ( self.type == INT and _is_base_n(v, 10) ) or 2921f219e013SMasahiro Yamada ( self.type == HEX and _is_base_n(v, 16) )): 2922f219e013SMasahiro Yamada 2923f219e013SMasahiro Yamada self.config._warn('the value "{0}" is invalid for {1}, which has type {2}. ' 2924f219e013SMasahiro Yamada "Assignment ignored." 2925f219e013SMasahiro Yamada .format(v, self.name, typename[self.type])) 2926f219e013SMasahiro Yamada return 2927f219e013SMasahiro Yamada 2928f219e013SMasahiro Yamada if self.prompts == [] and not suppress_load_warnings: 2929f219e013SMasahiro Yamada self.config._warn('assigning "{0}" to the symbol {1} which ' 2930f219e013SMasahiro Yamada 'lacks prompts and thus has visibility "n". ' 2931f219e013SMasahiro Yamada 'The assignment will have no effect.' 2932f219e013SMasahiro Yamada .format(v, self.name)) 2933f219e013SMasahiro Yamada 2934f219e013SMasahiro Yamada self.user_val = v 2935f219e013SMasahiro Yamada 2936f219e013SMasahiro Yamada if self.is_choice_symbol_ and (self.type == BOOL or 2937f219e013SMasahiro Yamada self.type == TRISTATE): 2938f219e013SMasahiro Yamada choice = self.parent 2939f219e013SMasahiro Yamada if v == "y": 2940f219e013SMasahiro Yamada choice.user_val = self 2941f219e013SMasahiro Yamada choice.user_mode = "y" 2942f219e013SMasahiro Yamada elif v == "m": 2943f219e013SMasahiro Yamada choice.user_val = None 2944f219e013SMasahiro Yamada choice.user_mode = "m" 2945f219e013SMasahiro Yamada 2946f219e013SMasahiro Yamada def _unset_user_value_no_recursive_invalidate(self): 2947f219e013SMasahiro Yamada self._invalidate() 2948f219e013SMasahiro Yamada self.user_val = None 2949f219e013SMasahiro Yamada 2950f219e013SMasahiro Yamada if self.is_choice_symbol_: 2951f219e013SMasahiro Yamada self.parent._unset_user_value() 2952f219e013SMasahiro Yamada 2953f219e013SMasahiro Yamada def _make_conf(self): 2954f219e013SMasahiro Yamada if self.already_written: 2955f219e013SMasahiro Yamada return [] 2956f219e013SMasahiro Yamada 2957f219e013SMasahiro Yamada self.already_written = True 2958f219e013SMasahiro Yamada 2959f219e013SMasahiro Yamada # Note: write_to_conf is determined in get_value() 2960f219e013SMasahiro Yamada val = self.get_value() 2961f219e013SMasahiro Yamada if not self.write_to_conf: 2962f219e013SMasahiro Yamada return [] 2963f219e013SMasahiro Yamada 2964f219e013SMasahiro Yamada if self.type == BOOL or self.type == TRISTATE: 2965f219e013SMasahiro Yamada if val == "m" or val == "y": 2966f219e013SMasahiro Yamada return ["CONFIG_{0}={1}".format(self.name, val)] 2967f219e013SMasahiro Yamada return ["# CONFIG_{0} is not set".format(self.name)] 2968f219e013SMasahiro Yamada 2969f219e013SMasahiro Yamada elif self.type == STRING: 2970f219e013SMasahiro Yamada # Escape \ and " 2971f219e013SMasahiro Yamada return ['CONFIG_{0}="{1}"' 2972f219e013SMasahiro Yamada .format(self.name, 2973f219e013SMasahiro Yamada val.replace("\\", "\\\\").replace('"', '\\"'))] 2974f219e013SMasahiro Yamada 2975f219e013SMasahiro Yamada elif self.type == INT or self.type == HEX: 2976f219e013SMasahiro Yamada return ["CONFIG_{0}={1}".format(self.name, val)] 2977f219e013SMasahiro Yamada 2978f219e013SMasahiro Yamada else: 2979f219e013SMasahiro Yamada _internal_error('Internal error while creating .config: unknown type "{0}".' 2980f219e013SMasahiro Yamada .format(self.type)) 2981f219e013SMasahiro Yamada 2982f219e013SMasahiro Yamada def _get_dependent(self): 2983f219e013SMasahiro Yamada """Returns the set of symbols that should be invalidated if the value 2984f219e013SMasahiro Yamada of the symbol changes, because they might be affected by the change. 2985f219e013SMasahiro Yamada Note that this is an internal API -- it's probably of limited 2986f219e013SMasahiro Yamada usefulness to clients.""" 2987f219e013SMasahiro Yamada if self.cached_deps is not None: 2988f219e013SMasahiro Yamada return self.cached_deps 2989f219e013SMasahiro Yamada 2990f219e013SMasahiro Yamada res = set() 2991f219e013SMasahiro Yamada 2992f219e013SMasahiro Yamada self._add_dependent_ignore_siblings(res) 2993f219e013SMasahiro Yamada if self.is_choice_symbol_: 2994f219e013SMasahiro Yamada for s in self.parent.get_symbols(): 2995f219e013SMasahiro Yamada if s is not self: 2996f219e013SMasahiro Yamada res.add(s) 2997f219e013SMasahiro Yamada s._add_dependent_ignore_siblings(res) 2998f219e013SMasahiro Yamada 2999f219e013SMasahiro Yamada self.cached_deps = res 3000f219e013SMasahiro Yamada return res 3001f219e013SMasahiro Yamada 3002f219e013SMasahiro Yamada def _add_dependent_ignore_siblings(self, to): 3003f219e013SMasahiro Yamada """Calculating dependencies gets a bit tricky for choice items as they 3004f219e013SMasahiro Yamada all depend on each other, potentially leading to infinite recursion. 3005f219e013SMasahiro Yamada This helper function calculates dependencies ignoring the other symbols 3006f219e013SMasahiro Yamada in the choice. It also works fine for symbols that are not choice 3007f219e013SMasahiro Yamada items.""" 3008f219e013SMasahiro Yamada for s in self.dep: 3009f219e013SMasahiro Yamada to.add(s) 3010f219e013SMasahiro Yamada to |= s._get_dependent() 3011f219e013SMasahiro Yamada 3012f219e013SMasahiro Yamada def _has_auto_menu_dep_on(self, on): 3013f219e013SMasahiro Yamada """See Choice._determine_actual_symbols().""" 3014f219e013SMasahiro Yamada if not isinstance(self.parent, Choice): 3015f219e013SMasahiro Yamada _internal_error("Attempt to determine auto menu dependency for symbol ouside of choice.") 3016f219e013SMasahiro Yamada 3017f219e013SMasahiro Yamada if self.prompts == []: 3018f219e013SMasahiro Yamada # If we have no prompt, use the menu dependencies instead (what was 3019f219e013SMasahiro Yamada # specified with 'depends on') 3020f219e013SMasahiro Yamada return self.menu_dep is not None and \ 3021f219e013SMasahiro Yamada self.config._expr_depends_on(self.menu_dep, on) 3022f219e013SMasahiro Yamada 3023f219e013SMasahiro Yamada for (_, cond_expr) in self.prompts: 3024f219e013SMasahiro Yamada if self.config._expr_depends_on(cond_expr, on): 3025f219e013SMasahiro Yamada return True 3026f219e013SMasahiro Yamada 3027f219e013SMasahiro Yamada return False 3028f219e013SMasahiro Yamada 3029f219e013SMasahiro Yamadaclass Menu(Item): 3030f219e013SMasahiro Yamada 3031f219e013SMasahiro Yamada """Represents a menu statement.""" 3032f219e013SMasahiro Yamada 3033f219e013SMasahiro Yamada # 3034f219e013SMasahiro Yamada # Public interface 3035f219e013SMasahiro Yamada # 3036f219e013SMasahiro Yamada 3037f219e013SMasahiro Yamada def get_config(self): 3038f219e013SMasahiro Yamada """Return the Config instance this menu is from.""" 3039f219e013SMasahiro Yamada return self.config 3040f219e013SMasahiro Yamada 3041f219e013SMasahiro Yamada def get_visibility(self): 3042f219e013SMasahiro Yamada """Returns the visibility of the menu. This also affects the visibility 3043f219e013SMasahiro Yamada of subitems. See also Symbol.get_visibility().""" 3044f219e013SMasahiro Yamada return self.config._eval_expr(self.dep_expr) 3045f219e013SMasahiro Yamada 3046f219e013SMasahiro Yamada def get_visible_if_visibility(self): 3047f219e013SMasahiro Yamada """Returns the visibility the menu gets from its 'visible if' 3048f219e013SMasahiro Yamada condition. "y" if the menu has no 'visible if' condition.""" 3049f219e013SMasahiro Yamada return self.config._eval_expr(self.visible_if_expr) 3050f219e013SMasahiro Yamada 3051f219e013SMasahiro Yamada def get_items(self, recursive = False): 3052f219e013SMasahiro Yamada """Returns a list containing the items (symbols, menus, choice 3053f219e013SMasahiro Yamada statements and comments) in in the menu, in the same order that the 3054f219e013SMasahiro Yamada items appear within the menu. 3055f219e013SMasahiro Yamada 3056f219e013SMasahiro Yamada recursive (default: False) -- True if items contained in items within 3057f219e013SMasahiro Yamada the menu should be included 3058f219e013SMasahiro Yamada recursively (preorder).""" 3059f219e013SMasahiro Yamada 3060f219e013SMasahiro Yamada if not recursive: 3061f219e013SMasahiro Yamada return self.block.get_items() 3062f219e013SMasahiro Yamada 3063f219e013SMasahiro Yamada res = [] 3064f219e013SMasahiro Yamada for item in self.block.get_items(): 3065f219e013SMasahiro Yamada res.append(item) 3066f219e013SMasahiro Yamada if isinstance(item, Menu): 3067f219e013SMasahiro Yamada res.extend(item.get_items(True)) 3068f219e013SMasahiro Yamada elif isinstance(item, Choice): 3069f219e013SMasahiro Yamada res.extend(item.get_items()) 3070f219e013SMasahiro Yamada return res 3071f219e013SMasahiro Yamada 3072f219e013SMasahiro Yamada def get_symbols(self, recursive = False): 3073f219e013SMasahiro Yamada """Returns a list containing the symbols in the menu, in the same order 3074f219e013SMasahiro Yamada that they appear within the menu. 3075f219e013SMasahiro Yamada 3076f219e013SMasahiro Yamada recursive (default: False) -- True if symbols contained in items within 3077f219e013SMasahiro Yamada the menu should be included 3078f219e013SMasahiro Yamada recursively.""" 3079f219e013SMasahiro Yamada 3080f219e013SMasahiro Yamada return [item for item in self.get_items(recursive) if isinstance(item, Symbol)] 3081f219e013SMasahiro Yamada 3082f219e013SMasahiro Yamada def get_title(self): 3083f219e013SMasahiro Yamada """Returns the title text of the menu.""" 3084f219e013SMasahiro Yamada return self.title 3085f219e013SMasahiro Yamada 3086f219e013SMasahiro Yamada def get_parent(self): 3087f219e013SMasahiro Yamada """Returns the menu or choice statement that contains the menu, or 3088f219e013SMasahiro Yamada None if the menu is at the top level. Note that if statements are 3089f219e013SMasahiro Yamada treated as syntactic sugar and do not have an explicit class 3090f219e013SMasahiro Yamada representation.""" 3091f219e013SMasahiro Yamada return self.parent 3092f219e013SMasahiro Yamada 3093f219e013SMasahiro Yamada def get_referenced_symbols(self, refs_from_enclosing = False): 3094f219e013SMasahiro Yamada """See Symbol.get_referenced_symbols().""" 3095f219e013SMasahiro Yamada return self.all_referenced_syms if refs_from_enclosing else self.referenced_syms 3096f219e013SMasahiro Yamada 3097f219e013SMasahiro Yamada def get_location(self): 3098f219e013SMasahiro Yamada """Returns the location of the menu as a (filename, linenr) tuple, 3099f219e013SMasahiro Yamada where filename is a string and linenr an int.""" 3100f219e013SMasahiro Yamada return (self.filename, self.linenr) 3101f219e013SMasahiro Yamada 3102f219e013SMasahiro Yamada def __str__(self): 3103f219e013SMasahiro Yamada """Returns a string containing various information about the menu.""" 3104f219e013SMasahiro Yamada depends_on_str = self.config._expr_val_str(self.orig_deps, 3105f219e013SMasahiro Yamada "(no dependencies)") 3106f219e013SMasahiro Yamada visible_if_str = self.config._expr_val_str(self.visible_if_expr, 3107f219e013SMasahiro Yamada "(no dependencies)") 3108f219e013SMasahiro Yamada 3109f219e013SMasahiro Yamada additional_deps_str = " " + self.config._expr_val_str(self.deps_from_containing, 3110f219e013SMasahiro Yamada "(no additional dependencies)") 3111f219e013SMasahiro Yamada 3112f219e013SMasahiro Yamada return _sep_lines("Menu", 3113f219e013SMasahiro Yamada "Title : " + self.title, 3114f219e013SMasahiro Yamada "'depends on' dependencies : " + depends_on_str, 3115f219e013SMasahiro Yamada "'visible if' dependencies : " + visible_if_str, 3116f219e013SMasahiro Yamada "Additional dependencies from enclosing menus and if's:", 3117f219e013SMasahiro Yamada additional_deps_str, 3118f219e013SMasahiro Yamada "Location: {0}:{1}".format(self.filename, self.linenr)) 3119f219e013SMasahiro Yamada 3120f219e013SMasahiro Yamada # 3121f219e013SMasahiro Yamada # Private methods 3122f219e013SMasahiro Yamada # 3123f219e013SMasahiro Yamada 3124f219e013SMasahiro Yamada def __init__(self): 3125f219e013SMasahiro Yamada """Menu constructor -- not intended to be called directly by 3126f219e013SMasahiro Yamada kconfiglib clients.""" 3127f219e013SMasahiro Yamada 3128f219e013SMasahiro Yamada self.config = None 3129f219e013SMasahiro Yamada 3130f219e013SMasahiro Yamada self.parent = None 3131f219e013SMasahiro Yamada self.title = None 3132f219e013SMasahiro Yamada self.block = None 3133f219e013SMasahiro Yamada self.dep_expr = None 3134f219e013SMasahiro Yamada 3135f219e013SMasahiro Yamada # Dependency expression without dependencies from enclosing menus and 3136f219e013SMasahiro Yamada # if's propagated 3137f219e013SMasahiro Yamada self.orig_deps = None 3138f219e013SMasahiro Yamada 3139f219e013SMasahiro Yamada # Dependencies inherited from containing menus and if's 3140f219e013SMasahiro Yamada self.deps_from_containing = None 3141f219e013SMasahiro Yamada 3142f219e013SMasahiro Yamada # The 'visible if' expression 3143f219e013SMasahiro Yamada self.visible_if_expr = None 3144f219e013SMasahiro Yamada 3145f219e013SMasahiro Yamada # The set of symbols referenced by this menu (see 3146f219e013SMasahiro Yamada # get_referenced_symbols()) 3147f219e013SMasahiro Yamada self.referenced_syms = set() 3148f219e013SMasahiro Yamada 3149f219e013SMasahiro Yamada # Like 'referenced_syms', but includes symbols from 3150f219e013SMasahiro Yamada # dependencies inherited from enclosing menus and if's 3151f219e013SMasahiro Yamada self.all_referenced_syms = None 3152f219e013SMasahiro Yamada 3153f219e013SMasahiro Yamada self.filename = None 3154f219e013SMasahiro Yamada self.linenr = None 3155f219e013SMasahiro Yamada 3156f219e013SMasahiro Yamada def _make_conf(self): 3157f219e013SMasahiro Yamada item_conf = self.block._make_conf() 3158f219e013SMasahiro Yamada 3159f219e013SMasahiro Yamada if self.config._eval_expr(self.dep_expr) != "n" and \ 3160f219e013SMasahiro Yamada self.config._eval_expr(self.visible_if_expr) != "n": 3161f219e013SMasahiro Yamada return ["\n#\n# {0}\n#".format(self.title)] + item_conf 3162f219e013SMasahiro Yamada return item_conf 3163f219e013SMasahiro Yamada 3164f219e013SMasahiro Yamadaclass Choice(Item, _HasVisibility): 3165f219e013SMasahiro Yamada 3166f219e013SMasahiro Yamada """Represents a choice statement. A choice can be in one of three modes: 3167f219e013SMasahiro Yamada 3168f219e013SMasahiro Yamada "n" - The choice is not visible and no symbols can be selected. 3169f219e013SMasahiro Yamada 3170f219e013SMasahiro Yamada "m" - Any number of symbols can be set to "m". The rest will be "n". This 3171f219e013SMasahiro Yamada is safe since potentially conflicting options don't actually get 3172f219e013SMasahiro Yamada compiled into the kernel simultaneously with "m". 3173f219e013SMasahiro Yamada 3174f219e013SMasahiro Yamada "y" - One symbol will be "y" while the rest are "n". 3175f219e013SMasahiro Yamada 3176f219e013SMasahiro Yamada Only tristate choices can be in "m" mode, and the visibility of the choice 3177f219e013SMasahiro Yamada is an upper bound on the mode, so that e.g. a choice that depends on a 3178f219e013SMasahiro Yamada symbol with value "m" will be in "m" mode. 3179f219e013SMasahiro Yamada 3180f219e013SMasahiro Yamada The mode changes automatically when a value is assigned to a symbol within 3181f219e013SMasahiro Yamada the choice. 3182f219e013SMasahiro Yamada 3183f219e013SMasahiro Yamada See Symbol.get_visibility() too.""" 3184f219e013SMasahiro Yamada 3185f219e013SMasahiro Yamada # 3186f219e013SMasahiro Yamada # Public interface 3187f219e013SMasahiro Yamada # 3188f219e013SMasahiro Yamada 3189f219e013SMasahiro Yamada def get_selection(self): 3190f219e013SMasahiro Yamada """Returns the symbol selected (either by the user or through 3191f219e013SMasahiro Yamada defaults), or None if either no symbol is selected or the mode is not 3192f219e013SMasahiro Yamada "y".""" 3193f219e013SMasahiro Yamada if self.cached_selection is not None: 3194f219e013SMasahiro Yamada if self.cached_selection == NO_SELECTION: 3195f219e013SMasahiro Yamada return None 3196f219e013SMasahiro Yamada return self.cached_selection 3197f219e013SMasahiro Yamada 3198f219e013SMasahiro Yamada if self.get_mode() != "y": 3199f219e013SMasahiro Yamada return self._cache_ret(None) 3200f219e013SMasahiro Yamada 3201f219e013SMasahiro Yamada # User choice available? 3202f219e013SMasahiro Yamada if self.user_val is not None and \ 3203f219e013SMasahiro Yamada self.user_val._get_visibility() == "y": 3204f219e013SMasahiro Yamada return self._cache_ret(self.user_val) 3205f219e013SMasahiro Yamada 3206f219e013SMasahiro Yamada if self.optional: 3207f219e013SMasahiro Yamada return self._cache_ret(None) 3208f219e013SMasahiro Yamada 3209f219e013SMasahiro Yamada return self._cache_ret(self.get_selection_from_defaults()) 3210f219e013SMasahiro Yamada 3211f219e013SMasahiro Yamada def get_selection_from_defaults(self): 3212f219e013SMasahiro Yamada """Like Choice.get_selection(), but acts as if no symbol has been 3213f219e013SMasahiro Yamada selected by the user and no 'optional' flag is in effect.""" 3214f219e013SMasahiro Yamada 3215f219e013SMasahiro Yamada if self.actual_symbols == []: 3216f219e013SMasahiro Yamada return None 3217f219e013SMasahiro Yamada 3218f219e013SMasahiro Yamada for (symbol, cond_expr) in self.def_exprs: 3219f219e013SMasahiro Yamada if self.config._eval_expr(cond_expr) != "n": 3220f219e013SMasahiro Yamada chosen_symbol = symbol 3221f219e013SMasahiro Yamada break 3222f219e013SMasahiro Yamada else: 3223f219e013SMasahiro Yamada chosen_symbol = self.actual_symbols[0] 3224f219e013SMasahiro Yamada 3225f219e013SMasahiro Yamada # Is the chosen symbol visible? 3226f219e013SMasahiro Yamada if chosen_symbol._get_visibility() != "n": 3227f219e013SMasahiro Yamada return chosen_symbol 3228f219e013SMasahiro Yamada # Otherwise, pick the first visible symbol 3229f219e013SMasahiro Yamada for sym in self.actual_symbols: 3230f219e013SMasahiro Yamada if sym._get_visibility() != "n": 3231f219e013SMasahiro Yamada return sym 3232f219e013SMasahiro Yamada return None 3233f219e013SMasahiro Yamada 3234f219e013SMasahiro Yamada def get_user_selection(self): 3235f219e013SMasahiro Yamada """If the choice is in "y" mode and has a user-selected symbol, returns 3236f219e013SMasahiro Yamada that symbol. Otherwise, returns None.""" 3237f219e013SMasahiro Yamada return self.user_val 3238f219e013SMasahiro Yamada 3239f219e013SMasahiro Yamada def get_config(self): 3240f219e013SMasahiro Yamada """Returns the Config instance this choice is from.""" 3241f219e013SMasahiro Yamada return self.config 3242f219e013SMasahiro Yamada 3243f219e013SMasahiro Yamada def get_name(self): 3244f219e013SMasahiro Yamada """For named choices, returns the name. Returns None for unnamed 3245f219e013SMasahiro Yamada choices. No named choices appear anywhere in the kernel Kconfig files 3246f219e013SMasahiro Yamada as of Linux 3.7.0-rc8.""" 3247f219e013SMasahiro Yamada return self.name 3248f219e013SMasahiro Yamada 3249f219e013SMasahiro Yamada def get_prompts(self): 3250f219e013SMasahiro Yamada """Returns a list of prompts defined for the choice, in the order they 3251f219e013SMasahiro Yamada appear in the configuration files. Returns the empty list for choices 3252f219e013SMasahiro Yamada with no prompt. 3253f219e013SMasahiro Yamada 3254f219e013SMasahiro Yamada This list will have a single entry for the vast majority of choices 3255f219e013SMasahiro Yamada having prompts, but having multiple prompts for a single choice is 3256f219e013SMasahiro Yamada possible through having multiple 'choice' entries for it (though I'm 3257f219e013SMasahiro Yamada not sure if that ever happens in practice).""" 3258f219e013SMasahiro Yamada return [prompt for prompt, _ in self.orig_prompts] 3259f219e013SMasahiro Yamada 3260f219e013SMasahiro Yamada def get_help(self): 3261f219e013SMasahiro Yamada """Returns the help text of the choice, or None if the choice has no 3262f219e013SMasahiro Yamada help text.""" 3263f219e013SMasahiro Yamada return self.help 3264f219e013SMasahiro Yamada 3265f219e013SMasahiro Yamada def get_type(self): 3266f219e013SMasahiro Yamada """Returns the type of the choice. See Symbol.get_type().""" 3267f219e013SMasahiro Yamada return self.type 3268f219e013SMasahiro Yamada 3269f219e013SMasahiro Yamada def get_items(self): 3270f219e013SMasahiro Yamada """Gets all items contained in the choice in the same order as within 3271f219e013SMasahiro Yamada the configuration ("items" instead of "symbols" since choices and 3272f219e013SMasahiro Yamada comments might appear within choices. This only happens in one place as 3273f219e013SMasahiro Yamada of Linux 3.7.0-rc8, in drivers/usb/gadget/Kconfig).""" 3274f219e013SMasahiro Yamada return self.block.get_items() 3275f219e013SMasahiro Yamada 3276f219e013SMasahiro Yamada def get_symbols(self): 3277f219e013SMasahiro Yamada """Returns a list containing the choice's symbols. 3278f219e013SMasahiro Yamada 3279f219e013SMasahiro Yamada A quirk (perhaps a bug) of Kconfig is that you can put items within a 3280f219e013SMasahiro Yamada choice that will not be considered members of the choice insofar as 3281f219e013SMasahiro Yamada selection is concerned. This happens for example if one symbol within a 3282f219e013SMasahiro Yamada choice 'depends on' the symbol preceding it, or if you put non-symbol 3283f219e013SMasahiro Yamada items within choices. 3284f219e013SMasahiro Yamada 3285f219e013SMasahiro Yamada As of Linux 3.7.0-rc8, this seems to be used intentionally in one 3286f219e013SMasahiro Yamada place: drivers/usb/gadget/Kconfig. 3287f219e013SMasahiro Yamada 3288f219e013SMasahiro Yamada This function returns the "proper" symbols of the choice in the order 3289f219e013SMasahiro Yamada they appear in the choice, excluding such items. If you want all items 3290f219e013SMasahiro Yamada in the choice, use get_items().""" 3291f219e013SMasahiro Yamada return self.actual_symbols 3292f219e013SMasahiro Yamada 3293f219e013SMasahiro Yamada def get_parent(self): 3294f219e013SMasahiro Yamada """Returns the menu or choice statement that contains the choice, or 3295f219e013SMasahiro Yamada None if the choice is at the top level. Note that if statements are 3296f219e013SMasahiro Yamada treated as syntactic sugar and do not have an explicit class 3297f219e013SMasahiro Yamada representation.""" 3298f219e013SMasahiro Yamada return self.parent 3299f219e013SMasahiro Yamada 3300f219e013SMasahiro Yamada def get_referenced_symbols(self, refs_from_enclosing = False): 3301f219e013SMasahiro Yamada """See Symbol.get_referenced_symbols().""" 3302f219e013SMasahiro Yamada return self.all_referenced_syms if refs_from_enclosing else self.referenced_syms 3303f219e013SMasahiro Yamada 3304f219e013SMasahiro Yamada def get_def_locations(self): 3305f219e013SMasahiro Yamada """Returns a list of (filename, linenr) tuples, where filename (string) 3306f219e013SMasahiro Yamada and linenr (int) represent a location where the choice is defined. For 3307f219e013SMasahiro Yamada the vast majority of choices (all of them as of Linux 3.7.0-rc8) this 3308f219e013SMasahiro Yamada list will only contain one element, but its possible for named choices 3309f219e013SMasahiro Yamada to be defined in multiple locations.""" 3310f219e013SMasahiro Yamada return self.def_locations 3311f219e013SMasahiro Yamada 3312f219e013SMasahiro Yamada def get_visibility(self): 3313f219e013SMasahiro Yamada """Returns the visibility of the choice statement: one of "n", "m" or 3314f219e013SMasahiro Yamada "y". This acts as an upper limit on the mode of the choice (though bool 3315f219e013SMasahiro Yamada choices can only have the mode "y"). See the class documentation for an 3316f219e013SMasahiro Yamada explanation of modes.""" 3317f219e013SMasahiro Yamada return self._get_visibility() 3318f219e013SMasahiro Yamada 3319f219e013SMasahiro Yamada def get_mode(self): 3320f219e013SMasahiro Yamada """Returns the mode of the choice. See the class documentation for 3321f219e013SMasahiro Yamada an explanation of modes.""" 3322f219e013SMasahiro Yamada minimum_mode = "n" if self.optional else "m" 3323f219e013SMasahiro Yamada mode = self.user_mode if self.user_mode is not None else minimum_mode 3324f219e013SMasahiro Yamada mode = self.config._eval_min(mode, self._get_visibility()) 3325f219e013SMasahiro Yamada 3326f219e013SMasahiro Yamada # Promote "m" to "y" for boolean choices 3327f219e013SMasahiro Yamada if mode == "m" and self.type == BOOL: 3328f219e013SMasahiro Yamada return "y" 3329f219e013SMasahiro Yamada 3330f219e013SMasahiro Yamada return mode 3331f219e013SMasahiro Yamada 3332f219e013SMasahiro Yamada def is_optional(self): 3333f219e013SMasahiro Yamada """Returns True if the symbol has the optional flag set (and so will default 3334f219e013SMasahiro Yamada to "n" mode). Otherwise, returns False.""" 3335f219e013SMasahiro Yamada return self.optional 3336f219e013SMasahiro Yamada 3337f219e013SMasahiro Yamada def __str__(self): 3338f219e013SMasahiro Yamada """Returns a string containing various information about the choice 3339f219e013SMasahiro Yamada statement.""" 3340f219e013SMasahiro Yamada return self.config._get_sym_or_choice_str(self) 3341f219e013SMasahiro Yamada 3342f219e013SMasahiro Yamada # 3343f219e013SMasahiro Yamada # Private methods 3344f219e013SMasahiro Yamada # 3345f219e013SMasahiro Yamada 3346f219e013SMasahiro Yamada def __init__(self): 3347f219e013SMasahiro Yamada """Choice constructor -- not intended to be called directly by 3348f219e013SMasahiro Yamada kconfiglib clients.""" 3349f219e013SMasahiro Yamada 3350f219e013SMasahiro Yamada _HasVisibility.__init__(self) 3351f219e013SMasahiro Yamada 3352f219e013SMasahiro Yamada self.config = None 3353f219e013SMasahiro Yamada 3354f219e013SMasahiro Yamada self.parent = None 3355f219e013SMasahiro Yamada self.name = None # Yes, choices can be named 3356f219e013SMasahiro Yamada self.type = UNKNOWN 3357f219e013SMasahiro Yamada self.def_exprs = [] 3358f219e013SMasahiro Yamada self.help = None 3359f219e013SMasahiro Yamada self.optional = False 3360f219e013SMasahiro Yamada self.block = None 3361f219e013SMasahiro Yamada 3362f219e013SMasahiro Yamada # The prompts and default values without any dependencies from 3363f219e013SMasahiro Yamada # enclosing menus or if's propagated 3364f219e013SMasahiro Yamada 3365f219e013SMasahiro Yamada self.orig_prompts = [] 3366f219e013SMasahiro Yamada self.orig_def_exprs = [] 3367f219e013SMasahiro Yamada 3368f219e013SMasahiro Yamada # Dependencies inherited from containing menus and if's 3369f219e013SMasahiro Yamada self.deps_from_containing = None 3370f219e013SMasahiro Yamada 3371f219e013SMasahiro Yamada # We need to filter out symbols that appear within the choice block but 3372f219e013SMasahiro Yamada # are not considered choice items (see 3373f219e013SMasahiro Yamada # Choice._determine_actual_symbols()) This list holds the "actual" choice 3374f219e013SMasahiro Yamada # items. 3375f219e013SMasahiro Yamada self.actual_symbols = [] 3376f219e013SMasahiro Yamada 3377f219e013SMasahiro Yamada # The set of symbols referenced by this choice (see 3378f219e013SMasahiro Yamada # get_referenced_symbols()) 3379f219e013SMasahiro Yamada self.referenced_syms = set() 3380f219e013SMasahiro Yamada 3381f219e013SMasahiro Yamada # Like 'referenced_syms', but includes symbols from 3382f219e013SMasahiro Yamada # dependencies inherited from enclosing menus and if's 3383f219e013SMasahiro Yamada self.all_referenced_syms = set() 3384f219e013SMasahiro Yamada 3385f219e013SMasahiro Yamada # See Choice.get_def_locations() 3386f219e013SMasahiro Yamada self.def_locations = [] 3387f219e013SMasahiro Yamada 3388f219e013SMasahiro Yamada self.user_val = None 3389f219e013SMasahiro Yamada self.user_mode = None 3390f219e013SMasahiro Yamada 3391f219e013SMasahiro Yamada self.cached_selection = None 3392f219e013SMasahiro Yamada 3393f219e013SMasahiro Yamada def _determine_actual_symbols(self): 3394f219e013SMasahiro Yamada """If a symbol's visibility depends on the preceding symbol within a 3395f219e013SMasahiro Yamada choice, it is no longer viewed as a choice item (quite possibly a bug, 3396f219e013SMasahiro Yamada but some things consciously use it.. ugh. It stems from automatic 3397f219e013SMasahiro Yamada submenu creation). In addition, it's possible to have choices and 3398f219e013SMasahiro Yamada comments within choices, and those shouldn't be considered as choice 3399f219e013SMasahiro Yamada items either. Only drivers/usb/gadget/Kconfig seems to depend on any of 3400f219e013SMasahiro Yamada this. This method computes the "actual" items in the choice and sets 3401f219e013SMasahiro Yamada the is_choice_symbol_ flag on them (retrieved via is_choice_symbol()). 3402f219e013SMasahiro Yamada 3403f219e013SMasahiro Yamada Don't let this scare you: an earlier version simply checked for a 3404f219e013SMasahiro Yamada sequence of symbols where all symbols after the first appeared in the 3405f219e013SMasahiro Yamada 'depends on' expression of the first, and that worked fine. The added 3406f219e013SMasahiro Yamada complexity is to be future-proof in the event that 3407f219e013SMasahiro Yamada drivers/usb/gadget/Kconfig turns even more sinister. It might very well 3408f219e013SMasahiro Yamada be overkilling things (especially if that file is refactored ;).""" 3409f219e013SMasahiro Yamada 3410f219e013SMasahiro Yamada items = self.block.get_items() 3411f219e013SMasahiro Yamada 3412f219e013SMasahiro Yamada # Items might depend on each other in a tree structure, so we need a 3413f219e013SMasahiro Yamada # stack to keep track of the current tentative parent 3414f219e013SMasahiro Yamada stack = [] 3415f219e013SMasahiro Yamada 3416f219e013SMasahiro Yamada for item in items: 3417f219e013SMasahiro Yamada if not isinstance(item, Symbol): 3418f219e013SMasahiro Yamada stack = [] 3419f219e013SMasahiro Yamada continue 3420f219e013SMasahiro Yamada 3421f219e013SMasahiro Yamada while stack != []: 3422f219e013SMasahiro Yamada if item._has_auto_menu_dep_on(stack[-1]): 3423f219e013SMasahiro Yamada # The item should not be viewed as a choice item, so don't 3424f219e013SMasahiro Yamada # set item.is_choice_symbol_. 3425f219e013SMasahiro Yamada stack.append(item) 3426f219e013SMasahiro Yamada break 3427f219e013SMasahiro Yamada else: 3428f219e013SMasahiro Yamada stack.pop() 3429f219e013SMasahiro Yamada else: 3430f219e013SMasahiro Yamada item.is_choice_symbol_ = True 3431f219e013SMasahiro Yamada self.actual_symbols.append(item) 3432f219e013SMasahiro Yamada stack.append(item) 3433f219e013SMasahiro Yamada 3434f219e013SMasahiro Yamada def _cache_ret(self, selection): 3435f219e013SMasahiro Yamada # As None is used to indicate the lack of a cached value we can't use 3436f219e013SMasahiro Yamada # that to cache the fact that the choice has no selection. Instead, we 3437f219e013SMasahiro Yamada # use the symbolic constant NO_SELECTION. 3438f219e013SMasahiro Yamada if selection is None: 3439f219e013SMasahiro Yamada self.cached_selection = NO_SELECTION 3440f219e013SMasahiro Yamada else: 3441f219e013SMasahiro Yamada self.cached_selection = selection 3442f219e013SMasahiro Yamada 3443f219e013SMasahiro Yamada return selection 3444f219e013SMasahiro Yamada 3445f219e013SMasahiro Yamada def _invalidate(self): 3446f219e013SMasahiro Yamada _HasVisibility._invalidate(self) 3447f219e013SMasahiro Yamada self.cached_selection = None 3448f219e013SMasahiro Yamada 3449f219e013SMasahiro Yamada def _unset_user_value(self): 3450f219e013SMasahiro Yamada self._invalidate() 3451f219e013SMasahiro Yamada self.user_val = None 3452f219e013SMasahiro Yamada self.user_mode = None 3453f219e013SMasahiro Yamada 3454f219e013SMasahiro Yamada def _make_conf(self): 3455f219e013SMasahiro Yamada return self.block._make_conf() 3456f219e013SMasahiro Yamada 3457f219e013SMasahiro Yamadaclass Comment(Item): 3458f219e013SMasahiro Yamada 3459f219e013SMasahiro Yamada """Represents a comment statement.""" 3460f219e013SMasahiro Yamada 3461f219e013SMasahiro Yamada # 3462f219e013SMasahiro Yamada # Public interface 3463f219e013SMasahiro Yamada # 3464f219e013SMasahiro Yamada 3465f219e013SMasahiro Yamada def get_config(self): 3466f219e013SMasahiro Yamada """Returns the Config instance this comment is from.""" 3467f219e013SMasahiro Yamada return self.config 3468f219e013SMasahiro Yamada 3469f219e013SMasahiro Yamada def get_visibility(self): 3470f219e013SMasahiro Yamada """Returns the visibility of the comment. See also 3471f219e013SMasahiro Yamada Symbol.get_visibility().""" 3472f219e013SMasahiro Yamada return self.config._eval_expr(self.dep_expr) 3473f219e013SMasahiro Yamada 3474f219e013SMasahiro Yamada def get_text(self): 3475f219e013SMasahiro Yamada """Returns the text of the comment.""" 3476f219e013SMasahiro Yamada return self.text 3477f219e013SMasahiro Yamada 3478f219e013SMasahiro Yamada def get_parent(self): 3479f219e013SMasahiro Yamada """Returns the menu or choice statement that contains the comment, or 3480f219e013SMasahiro Yamada None if the comment is at the top level. Note that if statements are 3481f219e013SMasahiro Yamada treated as syntactic sugar and do not have an explicit class 3482f219e013SMasahiro Yamada representation.""" 3483f219e013SMasahiro Yamada return self.parent 3484f219e013SMasahiro Yamada 3485f219e013SMasahiro Yamada def get_referenced_symbols(self, refs_from_enclosing = False): 3486f219e013SMasahiro Yamada """See Symbol.get_referenced_symbols().""" 3487f219e013SMasahiro Yamada return self.all_referenced_syms if refs_from_enclosing else self.referenced_syms 3488f219e013SMasahiro Yamada 3489f219e013SMasahiro Yamada def get_location(self): 3490f219e013SMasahiro Yamada """Returns the location of the comment as a (filename, linenr) tuple, 3491f219e013SMasahiro Yamada where filename is a string and linenr an int.""" 3492f219e013SMasahiro Yamada return (self.filename, self.linenr) 3493f219e013SMasahiro Yamada 3494f219e013SMasahiro Yamada def __str__(self): 3495f219e013SMasahiro Yamada """Returns a string containing various information about the comment.""" 3496f219e013SMasahiro Yamada dep_str = self.config._expr_val_str(self.orig_deps, "(no dependencies)") 3497f219e013SMasahiro Yamada 3498f219e013SMasahiro Yamada additional_deps_str = " " + self.config._expr_val_str(self.deps_from_containing, 3499f219e013SMasahiro Yamada "(no additional dependencies)") 3500f219e013SMasahiro Yamada 3501f219e013SMasahiro Yamada return _sep_lines("Comment", 3502f219e013SMasahiro Yamada "Text: " + str(self.text), 3503f219e013SMasahiro Yamada "Dependencies: " + dep_str, 3504f219e013SMasahiro Yamada "Additional dependencies from enclosing menus and if's:", 3505f219e013SMasahiro Yamada additional_deps_str, 3506f219e013SMasahiro Yamada "Location: {0}:{1}".format(self.filename, self.linenr)) 3507f219e013SMasahiro Yamada 3508f219e013SMasahiro Yamada # 3509f219e013SMasahiro Yamada # Private methods 3510f219e013SMasahiro Yamada # 3511f219e013SMasahiro Yamada 3512f219e013SMasahiro Yamada def __init__(self): 3513f219e013SMasahiro Yamada """Comment constructor -- not intended to be called directly by 3514f219e013SMasahiro Yamada kconfiglib clients.""" 3515f219e013SMasahiro Yamada 3516f219e013SMasahiro Yamada self.config = None 3517f219e013SMasahiro Yamada 3518f219e013SMasahiro Yamada self.parent = None 3519f219e013SMasahiro Yamada self.text = None 3520f219e013SMasahiro Yamada self.dep_expr = None 3521f219e013SMasahiro Yamada 3522f219e013SMasahiro Yamada # Dependency expression without dependencies from enclosing menus and 3523f219e013SMasahiro Yamada # if's propagated 3524f219e013SMasahiro Yamada self.orig_deps = None 3525f219e013SMasahiro Yamada 3526f219e013SMasahiro Yamada # Dependencies inherited from containing menus and if's 3527f219e013SMasahiro Yamada self.deps_from_containing = None 3528f219e013SMasahiro Yamada 3529f219e013SMasahiro Yamada # The set of symbols referenced by this comment (see 3530f219e013SMasahiro Yamada # get_referenced_symbols()) 3531f219e013SMasahiro Yamada self.referenced_syms = set() 3532f219e013SMasahiro Yamada 3533f219e013SMasahiro Yamada # Like 'referenced_syms', but includes symbols from 3534f219e013SMasahiro Yamada # dependencies inherited from enclosing menus and if's 3535f219e013SMasahiro Yamada self.all_referenced_syms = None 3536f219e013SMasahiro Yamada 3537f219e013SMasahiro Yamada self.filename = None 3538f219e013SMasahiro Yamada self.linenr = None 3539f219e013SMasahiro Yamada 3540f219e013SMasahiro Yamada def _make_conf(self): 3541f219e013SMasahiro Yamada if self.config._eval_expr(self.dep_expr) != "n": 3542f219e013SMasahiro Yamada return ["\n#\n# {0}\n#".format(self.text)] 3543f219e013SMasahiro Yamada return [] 3544f219e013SMasahiro Yamada 3545f219e013SMasahiro Yamadaclass _Feed: 3546f219e013SMasahiro Yamada 3547f219e013SMasahiro Yamada """Class for working with sequences in a stream-like fashion; handy for tokens.""" 3548f219e013SMasahiro Yamada 3549f219e013SMasahiro Yamada def __init__(self, items): 3550f219e013SMasahiro Yamada self.items = items 3551f219e013SMasahiro Yamada self.length = len(self.items) 3552f219e013SMasahiro Yamada self.i = 0 3553f219e013SMasahiro Yamada 3554f219e013SMasahiro Yamada def get_next(self): 3555f219e013SMasahiro Yamada if self.i >= self.length: 3556f219e013SMasahiro Yamada return None 3557f219e013SMasahiro Yamada 3558f219e013SMasahiro Yamada item = self.items[self.i] 3559f219e013SMasahiro Yamada self.i += 1 3560f219e013SMasahiro Yamada return item 3561f219e013SMasahiro Yamada 3562f219e013SMasahiro Yamada def peek_next(self): 3563f219e013SMasahiro Yamada return None if self.i >= self.length else self.items[self.i] 3564f219e013SMasahiro Yamada 3565f219e013SMasahiro Yamada def go_to_start(self): 3566f219e013SMasahiro Yamada self.i = 0 3567f219e013SMasahiro Yamada 3568f219e013SMasahiro Yamada def __getitem__(self, index): 3569f219e013SMasahiro Yamada return self.items[index] 3570f219e013SMasahiro Yamada 3571f219e013SMasahiro Yamada def __len__(self): 3572f219e013SMasahiro Yamada return len(self.items) 3573f219e013SMasahiro Yamada 3574f219e013SMasahiro Yamada def is_empty(self): 3575f219e013SMasahiro Yamada return self.items == [] 3576f219e013SMasahiro Yamada 3577f219e013SMasahiro Yamada def check(self, token): 3578f219e013SMasahiro Yamada """Check if the next token is 'token'. If so, remove it from the token 3579f219e013SMasahiro Yamada feed and return True. Otherwise, leave it in and return False.""" 3580f219e013SMasahiro Yamada if self.i >= self.length: 3581f219e013SMasahiro Yamada return None 3582f219e013SMasahiro Yamada 3583f219e013SMasahiro Yamada if self.items[self.i] == token: 3584f219e013SMasahiro Yamada self.i += 1 3585f219e013SMasahiro Yamada return True 3586f219e013SMasahiro Yamada 3587f219e013SMasahiro Yamada return False 3588f219e013SMasahiro Yamada 3589f219e013SMasahiro Yamada def remove_while(self, pred): 3590f219e013SMasahiro Yamada while self.i < self.length and pred(self.items[self.i]): 3591f219e013SMasahiro Yamada self.i += 1 3592f219e013SMasahiro Yamada 3593f219e013SMasahiro Yamada def go_back(self): 3594f219e013SMasahiro Yamada if self.i <= 0: 3595f219e013SMasahiro Yamada _internal_error("Attempt to move back in Feed while already at the beginning.") 3596f219e013SMasahiro Yamada self.i -= 1 3597f219e013SMasahiro Yamada 3598f219e013SMasahiro Yamadaclass _FileFeed(_Feed): 3599f219e013SMasahiro Yamada 3600f219e013SMasahiro Yamada """Feed subclass that keeps track of the current filename and line 3601f219e013SMasahiro Yamada number.""" 3602f219e013SMasahiro Yamada 3603f219e013SMasahiro Yamada def __init__(self, lines, filename): 3604f219e013SMasahiro Yamada self.filename = _clean_up_path(filename) 3605f219e013SMasahiro Yamada _Feed.__init__(self, lines) 3606f219e013SMasahiro Yamada 3607f219e013SMasahiro Yamada def get_filename(self): 3608f219e013SMasahiro Yamada return self.filename 3609f219e013SMasahiro Yamada 3610f219e013SMasahiro Yamada def get_linenr(self): 3611f219e013SMasahiro Yamada return self.i 3612f219e013SMasahiro Yamada 3613f219e013SMasahiro Yamada# 3614f219e013SMasahiro Yamada# Misc. public global utility functions 3615f219e013SMasahiro Yamada# 3616f219e013SMasahiro Yamada 3617f219e013SMasahiro Yamadadef tri_less(v1, v2): 3618f219e013SMasahiro Yamada """Returns True if the tristate v1 is less than the tristate v2, where "n", 3619f219e013SMasahiro Yamada "m" and "y" are ordered from lowest to highest. Otherwise, returns 3620f219e013SMasahiro Yamada False.""" 3621f219e013SMasahiro Yamada return tri_to_int[v1] < tri_to_int[v2] 3622f219e013SMasahiro Yamada 3623f219e013SMasahiro Yamadadef tri_less_eq(v1, v2): 3624f219e013SMasahiro Yamada """Returns True if the tristate v1 is less than or equal to the tristate 3625f219e013SMasahiro Yamada v2, where "n", "m" and "y" are ordered from lowest to highest. Otherwise, 3626f219e013SMasahiro Yamada returns False.""" 3627f219e013SMasahiro Yamada return tri_to_int[v1] <= tri_to_int[v2] 3628f219e013SMasahiro Yamada 3629f219e013SMasahiro Yamadadef tri_greater(v1, v2): 3630f219e013SMasahiro Yamada """Returns True if the tristate v1 is greater than the tristate v2, where 3631f219e013SMasahiro Yamada "n", "m" and "y" are ordered from lowest to highest. Otherwise, returns 3632f219e013SMasahiro Yamada False.""" 3633f219e013SMasahiro Yamada return tri_to_int[v1] > tri_to_int[v2] 3634f219e013SMasahiro Yamada 3635f219e013SMasahiro Yamadadef tri_greater_eq(v1, v2): 3636f219e013SMasahiro Yamada """Returns True if the tristate v1 is greater than or equal to the tristate 3637f219e013SMasahiro Yamada v2, where "n", "m" and "y" are ordered from lowest to highest. Otherwise, 3638f219e013SMasahiro Yamada returns False.""" 3639f219e013SMasahiro Yamada return tri_to_int[v1] >= tri_to_int[v2] 3640f219e013SMasahiro Yamada 3641f219e013SMasahiro Yamada# 3642f219e013SMasahiro Yamada# Helper functions, mostly related to text processing 3643f219e013SMasahiro Yamada# 3644f219e013SMasahiro Yamada 3645f219e013SMasahiro Yamadadef _strip_quotes(s, line, filename, linenr): 3646f219e013SMasahiro Yamada """Removes any quotes surrounding 's' if it has them; otherwise returns 's' 3647f219e013SMasahiro Yamada unmodified.""" 3648f219e013SMasahiro Yamada s = s.strip() 3649f219e013SMasahiro Yamada if not s: 3650f219e013SMasahiro Yamada return "" 3651f219e013SMasahiro Yamada if s[0] == '"' or s[0] == "'": 3652f219e013SMasahiro Yamada if len(s) < 2 or s[-1] != s[0]: 3653f219e013SMasahiro Yamada _parse_error(line, 3654f219e013SMasahiro Yamada "malformed string literal", 3655f219e013SMasahiro Yamada filename, 3656f219e013SMasahiro Yamada linenr) 3657f219e013SMasahiro Yamada return s[1:-1] 3658f219e013SMasahiro Yamada return s 3659f219e013SMasahiro Yamada 3660f219e013SMasahiro Yamadadef _indentation(line): 3661f219e013SMasahiro Yamada """Returns the indentation of the line, treating tab stops as being spaced 3662f219e013SMasahiro Yamada 8 characters apart.""" 3663f219e013SMasahiro Yamada if line.isspace(): 3664f219e013SMasahiro Yamada _internal_error("Attempt to take indentation of blank line.") 3665f219e013SMasahiro Yamada indent = 0 3666f219e013SMasahiro Yamada for c in line: 3667f219e013SMasahiro Yamada if c == " ": 3668f219e013SMasahiro Yamada indent += 1 3669f219e013SMasahiro Yamada elif c == "\t": 3670f219e013SMasahiro Yamada # Go to the next tab stop 3671f219e013SMasahiro Yamada indent = (indent + 8) & ~7 3672f219e013SMasahiro Yamada else: 3673f219e013SMasahiro Yamada return indent 3674f219e013SMasahiro Yamada 3675f219e013SMasahiro Yamadadef _deindent(line, indent): 3676f219e013SMasahiro Yamada """Deindent 'line' by 'indent' spaces.""" 3677f219e013SMasahiro Yamada line = line.expandtabs() 3678f219e013SMasahiro Yamada if len(line) <= indent: 3679f219e013SMasahiro Yamada return line 3680f219e013SMasahiro Yamada return line[indent:] 3681f219e013SMasahiro Yamada 3682f219e013SMasahiro Yamadadef _is_base_n(s, n): 3683f219e013SMasahiro Yamada try: 3684f219e013SMasahiro Yamada int(s, n) 3685f219e013SMasahiro Yamada return True 3686f219e013SMasahiro Yamada except ValueError: 3687f219e013SMasahiro Yamada return False 3688f219e013SMasahiro Yamada 3689f219e013SMasahiro Yamadadef _sep_lines(*args): 3690f219e013SMasahiro Yamada """Returns a string comprised of all arguments, with newlines inserted 3691f219e013SMasahiro Yamada between them.""" 3692f219e013SMasahiro Yamada return "\n".join(args) 3693f219e013SMasahiro Yamada 3694f219e013SMasahiro Yamadadef _comment(s): 3695f219e013SMasahiro Yamada """Returns a new string with "#" inserted before each line in 's'.""" 3696f219e013SMasahiro Yamada if not s: 3697f219e013SMasahiro Yamada return "#" 3698f219e013SMasahiro Yamada res = "".join(["#" + line for line in s.splitlines(True)]) 3699f219e013SMasahiro Yamada if s.endswith("\n"): 3700f219e013SMasahiro Yamada return res + "#" 3701f219e013SMasahiro Yamada return res 3702f219e013SMasahiro Yamada 3703f219e013SMasahiro Yamadadef _get_lines(filename): 3704f219e013SMasahiro Yamada """Returns a list of lines from 'filename', joining any line ending in \\ 3705f219e013SMasahiro Yamada with the following line.""" 3706f219e013SMasahiro Yamada with open(filename, "r") as f: 3707f219e013SMasahiro Yamada lines = [] 3708f219e013SMasahiro Yamada accum = "" 3709f219e013SMasahiro Yamada while 1: 3710f219e013SMasahiro Yamada line = f.readline() 3711f219e013SMasahiro Yamada 3712f219e013SMasahiro Yamada if line == "": 3713f219e013SMasahiro Yamada return lines 3714f219e013SMasahiro Yamada 3715f219e013SMasahiro Yamada if line.endswith("\\\n"): 3716f219e013SMasahiro Yamada accum += line[:-2] 3717f219e013SMasahiro Yamada else: 3718f219e013SMasahiro Yamada accum += line 3719f219e013SMasahiro Yamada lines.append(accum) 3720f219e013SMasahiro Yamada accum = "" 3721f219e013SMasahiro Yamada 3722f219e013SMasahiro Yamadadef _strip_trailing_slash(path): 3723f219e013SMasahiro Yamada """Removes any trailing slash from 'path'.""" 3724f219e013SMasahiro Yamada return path[:-1] if path.endswith("/") else path 3725f219e013SMasahiro Yamada 3726f219e013SMasahiro Yamadadef _clean_up_path(path): 3727f219e013SMasahiro Yamada """Strips any initial "./" and trailing slash from 'path'.""" 3728f219e013SMasahiro Yamada if path.startswith("./"): 3729f219e013SMasahiro Yamada path = path[2:] 3730f219e013SMasahiro Yamada return _strip_trailing_slash(path) 3731f219e013SMasahiro Yamada 3732f219e013SMasahiro Yamada# 3733f219e013SMasahiro Yamada# Error handling 3734f219e013SMasahiro Yamada# 3735f219e013SMasahiro Yamada 3736f219e013SMasahiro Yamadaclass Kconfig_Syntax_Error(Exception): 3737f219e013SMasahiro Yamada """Exception raised for syntax errors.""" 3738f219e013SMasahiro Yamada pass 3739f219e013SMasahiro Yamada 3740f219e013SMasahiro Yamadaclass Internal_Error(Exception): 3741f219e013SMasahiro Yamada """Exception raised for internal errors.""" 3742f219e013SMasahiro Yamada pass 3743f219e013SMasahiro Yamada 3744f219e013SMasahiro Yamadadef _tokenization_error(s, index, filename, linenr): 3745f219e013SMasahiro Yamada if filename is not None: 3746f219e013SMasahiro Yamada assert linenr is not None 3747f219e013SMasahiro Yamada sys.stderr.write("{0}:{1}:\n".format(filename, linenr)) 3748f219e013SMasahiro Yamada 3749f219e013SMasahiro Yamada if s.endswith("\n"): 3750f219e013SMasahiro Yamada s = s[:-1] 3751f219e013SMasahiro Yamada 3752f219e013SMasahiro Yamada # Calculate the visual offset corresponding to index 'index' in 's' 3753f219e013SMasahiro Yamada # assuming tabstops are spaced 8 characters apart 3754f219e013SMasahiro Yamada vis_index = 0 3755f219e013SMasahiro Yamada for c in s[:index]: 3756f219e013SMasahiro Yamada if c == "\t": 3757f219e013SMasahiro Yamada vis_index = (vis_index + 8) & ~7 3758f219e013SMasahiro Yamada else: 3759f219e013SMasahiro Yamada vis_index += 1 3760f219e013SMasahiro Yamada 3761f219e013SMasahiro Yamada # Don't output actual tabs to be independent of how the terminal renders 3762f219e013SMasahiro Yamada # them 3763f219e013SMasahiro Yamada s = s.expandtabs() 3764f219e013SMasahiro Yamada 3765f219e013SMasahiro Yamada raise Kconfig_Syntax_Error, ( 3766f219e013SMasahiro Yamada _sep_lines("Error during tokenization at location indicated by caret.\n", 3767f219e013SMasahiro Yamada s, 3768f219e013SMasahiro Yamada " " * vis_index + "^\n")) 3769f219e013SMasahiro Yamada 3770f219e013SMasahiro Yamadadef _parse_error(s, msg, filename, linenr): 3771f219e013SMasahiro Yamada error_str = "" 3772f219e013SMasahiro Yamada 3773f219e013SMasahiro Yamada if filename is not None: 3774f219e013SMasahiro Yamada assert linenr is not None 3775f219e013SMasahiro Yamada error_str += "{0}:{1}: ".format(filename, linenr) 3776f219e013SMasahiro Yamada 3777f219e013SMasahiro Yamada if s.endswith("\n"): 3778f219e013SMasahiro Yamada s = s[:-1] 3779f219e013SMasahiro Yamada 3780f219e013SMasahiro Yamada error_str += 'Error while parsing "{0}"'.format(s) + \ 3781f219e013SMasahiro Yamada ("." if msg is None else ": " + msg) 3782f219e013SMasahiro Yamada 3783f219e013SMasahiro Yamada raise Kconfig_Syntax_Error, error_str 3784f219e013SMasahiro Yamada 3785f219e013SMasahiro Yamadadef _internal_error(msg): 3786f219e013SMasahiro Yamada msg += "\nSorry! You may want to send an email to kconfiglib@gmail.com " \ 3787f219e013SMasahiro Yamada "to tell me about this. Include the message above and the stack " \ 3788f219e013SMasahiro Yamada "trace and describe what you were doing." 3789f219e013SMasahiro Yamada 3790f219e013SMasahiro Yamada raise Internal_Error, msg 3791f219e013SMasahiro Yamada 3792f219e013SMasahiro Yamadaif use_psyco: 3793f219e013SMasahiro Yamada import psyco 3794f219e013SMasahiro Yamada 3795f219e013SMasahiro Yamada Config._tokenize = psyco.proxy(Config._tokenize) 3796f219e013SMasahiro Yamada Config._eval_expr = psyco.proxy(Config._eval_expr) 3797f219e013SMasahiro Yamada 3798f219e013SMasahiro Yamada _indentation = psyco.proxy(_indentation) 3799f219e013SMasahiro Yamada _get_lines = psyco.proxy(_get_lines) 3800