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