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