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