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