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