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