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