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