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