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