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