From 3cba566b908398b905f7e7229f4dc275db392cc0 Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Mon, 8 Jun 2015 16:13:26 +0200 Subject: Clean up global ordering. kconfiglib.py is now arranged as follows: Public classes Public functions Internal classes Internal functions Internal global constants Bit arbitrary, but better than no ordering like before. :) --- kconfiglib.py | 807 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 409 insertions(+), 398 deletions(-) (limited to 'kconfiglib.py') diff --git a/kconfiglib.py b/kconfiglib.py index dc94da5..b421f87 100644 --- a/kconfiglib.py +++ b/kconfiglib.py @@ -70,6 +70,18 @@ import os import re import sys +# File layout: +# +# Public classes (and the Symbol and Choice base class _HasVisibility) +# Public functions +# Internal classes +# Internal functions +# Internal global constants + +# +# Public classes +# + class Config(object): """Represents a Kconfig configuration, e.g. for i386 or ARM. This is the @@ -1773,396 +1785,139 @@ class Config(object): if self.print_warnings: _stderr_msg("warning: " + msg, filename, linenr) -# -# Functions and constants related to types, expressions, parsing, evaluation -# and printing -# +class Item(object): -def _make_and(e1, e2): - """Constructs an AND (&&) expression. Performs trivial simplification. - Nones equate to 'y'. + """Base class for symbols and other Kconfig constructs. Subclasses are + Symbol, Choice, Menu, and Comment.""" - Note: returns None if e1 == e2 == None.""" - if e1 == "n" or e2 == "n": - return "n" - if e1 is None or e1 == "y": - return e2 - if e2 is None or e2 == "y": - return e1 + def is_symbol(self): + """Returns True if the item is a symbol. Short for + isinstance(item, kconfiglib.Symbol).""" + return isinstance(self, Symbol) - # Prefer to merge/update argument list if possible instead of creating - # a new AND node + def is_choice(self): + """Returns True if the item is a choice. Short for + isinstance(item, kconfiglib.Choice).""" + return isinstance(self, Choice) - if isinstance(e1, tuple) and e1[0] == AND: - if isinstance(e2, tuple) and e2[0] == AND: - return (AND, e1[1] + e2[1]) - return (AND, e1[1] + [e2]) + def is_menu(self): + """Returns True if the item is a menu. Short for + isinstance(item, kconfiglib.Menu).""" + return isinstance(self, Menu) - if isinstance(e2, tuple) and e2[0] == AND: - return (AND, e2[1] + [e1]) + def is_comment(self): + """Returns True if the item is a comment. Short for + isinstance(item, kconfiglib.Comment).""" + return isinstance(self, Comment) - return (AND, [e1, e2]) +class _HasVisibility(object): -def _make_or(e1, e2): - """Constructs an OR (||) expression. Performs trivial simplification and - avoids Nones. Nones equate to 'y', which is usually what we want, but needs - to be kept in mind.""" + """Base class for elements that have a "visibility" that acts as an upper + limit on the values a user can set for them. Subclasses are Symbol and + Choice (which supply some of the attributes).""" - # Perform trivial simplification and avoid None's (which - # correspond to y's) - if e1 is None or e2 is None or e1 == "y" or e2 == "y": - return "y" - if e1 == "n": - return e2 - if e2 == "n": - return e1 + def __init__(self): + self.cached_visibility = None + self.prompts = [] - # Prefer to merge/update argument list if possible instead of creating - # a new OR node + def _invalidate(self): + self.cached_visibility = None - if isinstance(e1, tuple) and e1[0] == OR: - if isinstance(e2, tuple) and e2[0] == OR: - return (OR, e1[1] + e2[1]) - return (OR, e1[1] + [e2]) + def _get_visibility(self): + if self.cached_visibility is None: + vis = "n" + for _, cond_expr in self.prompts: + vis = self.config._eval_max(vis, cond_expr) - if isinstance(e2, tuple) and e2[0] == OR: - return (OR, e2[1] + [e1]) + if isinstance(self, Symbol) and self.is_choice_symbol_: + vis = self.config._eval_min(vis, self.parent._get_visibility()) - return (OR, [e1, e2]) + # Promote "m" to "y" if we're dealing with a non-tristate + if vis == "m" and self.type != TRISTATE: + vis = "y" -def _get_expr_syms(expr): - """Returns the set() of symbols appearing in expr.""" - res = set() - if expr is None: - return res + self.cached_visibility = vis - def rec(expr): - if isinstance(expr, Symbol): - res.add(expr) - return - if isinstance(expr, str): - return + return self.cached_visibility - e0 = expr[0] - if e0 == AND or e0 == OR: - for term in expr[1]: - rec(term) - elif e0 == NOT: - rec(expr[1]) - elif e0 == EQUAL or e0 == UNEQUAL: - _, v1, v2 = expr - if isinstance(v1, Symbol): - res.add(v1) - if isinstance(v2, Symbol): - res.add(v2) - else: - _internal_error("Internal error while fetching symbols from an " - "expression with token stream {0}.".format(expr)) +class Symbol(Item, _HasVisibility): - rec(expr) - return res + """Represents a configuration symbol - e.g. FOO for -def _str_val(obj): - """Returns the value of obj as a string. If obj is not a string (constant - symbol), it must be a Symbol.""" - return obj if isinstance(obj, str) else obj.get_value() + config FOO + ...""" -def _sym_str_string(sym_or_str): - if isinstance(sym_or_str, str): - return '"' + sym_or_str + '"' - return sym_or_str.name + # + # Public interface + # -def _intersperse(lst, op): - """_expr_to_str() helper. Gets the string representation of each expression in lst - and produces a list where op has been inserted between the elements.""" - if lst == []: - return "" + def get_value(self): + """Calculate and return the value of the symbol. See also + Symbol.set_user_value().""" - res = [] + if self.cached_val is not None: + return self.cached_val - def handle_sub_expr(expr): - no_parens = isinstance(expr, (str, Symbol)) or \ - expr[0] in (EQUAL, UNEQUAL) or \ - precedence[op] <= precedence[expr[0]] - if not no_parens: - res.append("(") - res.extend(_expr_to_str_rec(expr)) - if not no_parens: - res.append(")") + self.write_to_conf = False - op_str = op_to_str[op] + # As a quirk of Kconfig, undefined symbols get their name as their + # value. This is why things like "FOO = bar" work for seeing if FOO has + # the value "bar". + if self.type == UNKNOWN: + self.cached_val = self.name + return self.name - handle_sub_expr(lst[0]) - for expr in lst[1:]: - res.append(op_str) - handle_sub_expr(expr) + new_val = default_value[self.type] - return res + vis = self._get_visibility() -def _expr_to_str_rec(expr): - if expr is None: - return [""] + if self.type == BOOL or self.type == TRISTATE: + # The visibility and mode (modules-only or single-selection) of + # choice items will be taken into account in self._get_visibility() + if self.is_choice_symbol_: + if vis != "n": + choice = self.parent + mode = choice.get_mode() - if isinstance(expr, (Symbol, str)): - return [_sym_str_string(expr)] + self.write_to_conf = (mode != "n") - e0 = expr[0] + if mode == "y": + new_val = "y" if (choice.get_selection() is self) else "n" + elif mode == "m": + if self.user_val == "m" or self.user_val == "y": + new_val = "m" - if e0 == AND or e0 == OR: - return _intersperse(expr[1], expr[0]) + else: + # If the symbol is visible and has a user value, use that. + # Otherwise, look at defaults. + use_defaults = True - if e0 == NOT: - need_parens = not isinstance(expr[1], (str, Symbol)) + if vis != "n": + self.write_to_conf = True + if self.user_val is not None: + new_val = self.config._eval_min(self.user_val, vis) + use_defaults = False - res = ["!"] - if need_parens: - res.append("(") - res.extend(_expr_to_str_rec(expr[1])) - if need_parens: - res.append(")") - return res + if use_defaults: + for val_expr, cond_expr in self.def_exprs: + cond_eval = self.config._eval_expr(cond_expr) + if cond_eval != "n": + self.write_to_conf = True + new_val = self.config._eval_min(val_expr, cond_eval) + break - if e0 == EQUAL or e0 == UNEQUAL: - return [_sym_str_string(expr[1]), - op_to_str[expr[0]], - _sym_str_string(expr[2])] + # Reverse (select-related) dependencies take precedence + rev_dep_val = self.config._eval_expr(self.rev_dep) + if rev_dep_val != "n": + self.write_to_conf = True + new_val = self.config._eval_max(new_val, rev_dep_val) -def _expr_to_str(expr): - return "".join(_expr_to_str_rec(expr)) + # Promote "m" to "y" for booleans + if new_val == "m" and self.type == BOOL: + new_val = "y" -# Tokens -(T_AND, T_OR, T_NOT, - T_OPEN_PAREN, T_CLOSE_PAREN, - T_EQUAL, T_UNEQUAL, - T_MAINMENU, T_MENU, T_ENDMENU, - T_SOURCE, T_CHOICE, T_ENDCHOICE, - T_COMMENT, T_CONFIG, T_MENUCONFIG, - T_HELP, T_IF, T_ENDIF, T_DEPENDS, T_ON, - T_OPTIONAL, T_PROMPT, T_DEFAULT, - T_BOOL, T_TRISTATE, T_HEX, T_INT, T_STRING, - T_DEF_BOOL, T_DEF_TRISTATE, - T_SELECT, T_RANGE, T_OPTION, T_ALLNOCONFIG_Y, T_ENV, - T_DEFCONFIG_LIST, T_MODULES, T_VISIBLE) = range(0, 39) - -# Keyword to token map. Note that the get() method is assigned directly as a -# small optimization. -get_keyword = { "mainmenu" : T_MAINMENU, - "menu" : T_MENU, - "endmenu" : T_ENDMENU, - "endif" : T_ENDIF, - "endchoice" : T_ENDCHOICE, - "source" : T_SOURCE, - "choice" : T_CHOICE, - "config" : T_CONFIG, - "comment" : T_COMMENT, - "menuconfig" : T_MENUCONFIG, - "help" : T_HELP, - "if" : T_IF, - "depends" : T_DEPENDS, - "on" : T_ON, - "optional" : T_OPTIONAL, - "prompt" : T_PROMPT, - "default" : T_DEFAULT, - "bool" : T_BOOL, - "boolean" : T_BOOL, - "tristate" : T_TRISTATE, - "int" : T_INT, - "hex" : T_HEX, - "def_bool" : T_DEF_BOOL, - "def_tristate" : T_DEF_TRISTATE, - "string" : T_STRING, - "select" : T_SELECT, - "range" : T_RANGE, - "option" : T_OPTION, - "allnoconfig_y" : T_ALLNOCONFIG_Y, - "env" : T_ENV, - "defconfig_list" : T_DEFCONFIG_LIST, - "modules" : T_MODULES, - "visible" : T_VISIBLE }.get - -# Strings to use for True and False -bool_str = { False : "false", True : "true" } - -# Tokens after which identifier-like lexemes are treated as strings. T_CHOICE -# is included to avoid symbols being registered for named choices. -string_lex = frozenset((T_BOOL, T_TRISTATE, T_INT, T_HEX, T_STRING, T_CHOICE, - T_PROMPT, T_MENU, T_COMMENT, T_SOURCE, T_MAINMENU)) - -# Matches the initial token on a line; see _tokenize(). -initial_token_re_match = re.compile(r"[^\w]*(\w+)").match - -# Matches an identifier/keyword optionally preceded by whitespace -id_keyword_re_match = re.compile(r"\s*([\w./-]+)").match - -# Regular expressions for parsing .config files -set_re_match = re.compile(r"CONFIG_(\w+)=(.*)").match -unset_re_match = re.compile(r"# CONFIG_(\w+) is not set").match - -# Regular expression for finding $-references to symbols in strings -sym_ref_re_search = re.compile(r"\$[A-Za-z0-9_]+").search - -# Integers representing symbol types -UNKNOWN, BOOL, TRISTATE, STRING, HEX, INT = range(0, 6) - -# Strings to use for types -typename = { UNKNOWN : "unknown", BOOL : "bool", TRISTATE : "tristate", - STRING : "string", HEX : "hex", INT : "int" } - -# Token to type mapping -token_to_type = { T_BOOL : BOOL, T_TRISTATE : TRISTATE, T_STRING : STRING, - T_INT : INT, T_HEX : HEX } - -# Default values for symbols of different types (the value the symbol gets if -# it is not assigned a user value and none of its 'default' clauses kick in) -default_value = { BOOL : "n", TRISTATE : "n", STRING : "", INT : "", HEX : "" } - -# Indicates that no item is selected in a choice statement -NO_SELECTION = 0 - -# Integers representing expression types -AND, OR, NOT, EQUAL, UNEQUAL = range(0, 5) - -# Map from tristate values to integers -tri_to_int = { "n" : 0, "m" : 1, "y" : 2 } - -# Printing-related stuff - -op_to_str = { AND : " && ", OR : " || ", EQUAL : " = ", UNEQUAL : " != " } -precedence = { OR : 0, AND : 1, NOT : 2 } - -class Item(object): - - """Base class for symbols and other Kconfig constructs. Subclasses are - Symbol, Choice, Menu, and Comment.""" - - def is_symbol(self): - """Returns True if the item is a symbol. Short for - isinstance(item, kconfiglib.Symbol).""" - return isinstance(self, Symbol) - - def is_choice(self): - """Returns True if the item is a choice. Short for - isinstance(item, kconfiglib.Choice).""" - return isinstance(self, Choice) - - def is_menu(self): - """Returns True if the item is a menu. Short for - isinstance(item, kconfiglib.Menu).""" - return isinstance(self, Menu) - - def is_comment(self): - """Returns True if the item is a comment. Short for - isinstance(item, kconfiglib.Comment).""" - return isinstance(self, Comment) - -class _HasVisibility(object): - - """Base class for elements that have a "visibility" that acts as an upper - limit on the values a user can set for them. Subclasses are Symbol and - Choice (which supply some of the attributes).""" - - def __init__(self): - self.cached_visibility = None - self.prompts = [] - - def _invalidate(self): - self.cached_visibility = None - - def _get_visibility(self): - if self.cached_visibility is None: - vis = "n" - for _, cond_expr in self.prompts: - vis = self.config._eval_max(vis, cond_expr) - - if isinstance(self, Symbol) and self.is_choice_symbol_: - vis = self.config._eval_min(vis, self.parent._get_visibility()) - - # Promote "m" to "y" if we're dealing with a non-tristate - if vis == "m" and self.type != TRISTATE: - vis = "y" - - self.cached_visibility = vis - - return self.cached_visibility - -class Symbol(Item, _HasVisibility): - - """Represents a configuration symbol - e.g. FOO for - - config FOO - ...""" - - # - # Public interface - # - - def get_value(self): - """Calculate and return the value of the symbol. See also - Symbol.set_user_value().""" - - if self.cached_val is not None: - return self.cached_val - - self.write_to_conf = False - - # As a quirk of Kconfig, undefined symbols get their name as their - # value. This is why things like "FOO = bar" work for seeing if FOO has - # the value "bar". - if self.type == UNKNOWN: - self.cached_val = self.name - return self.name - - new_val = default_value[self.type] - - vis = self._get_visibility() - - if self.type == BOOL or self.type == TRISTATE: - # The visibility and mode (modules-only or single-selection) of - # choice items will be taken into account in self._get_visibility() - if self.is_choice_symbol_: - if vis != "n": - choice = self.parent - mode = choice.get_mode() - - self.write_to_conf = (mode != "n") - - if mode == "y": - new_val = "y" if (choice.get_selection() is self) else "n" - elif mode == "m": - if self.user_val == "m" or self.user_val == "y": - new_val = "m" - - else: - # If the symbol is visible and has a user value, use that. - # Otherwise, look at defaults. - use_defaults = True - - if vis != "n": - self.write_to_conf = True - if self.user_val is not None: - new_val = self.config._eval_min(self.user_val, vis) - use_defaults = False - - if use_defaults: - for val_expr, cond_expr in self.def_exprs: - cond_eval = self.config._eval_expr(cond_expr) - if cond_eval != "n": - self.write_to_conf = True - new_val = self.config._eval_min(val_expr, cond_eval) - break - - # Reverse (select-related) dependencies take precedence - rev_dep_val = self.config._eval_expr(self.rev_dep) - if rev_dep_val != "n": - self.write_to_conf = True - new_val = self.config._eval_max(new_val, rev_dep_val) - - # Promote "m" to "y" for booleans - if new_val == "m" and self.type == BOOL: - new_val = "y" - - elif self.type == STRING: - use_defaults = True + elif self.type == STRING: + use_defaults = True if vis != "n": self.write_to_conf = True @@ -3342,16 +3097,41 @@ class Comment(Item): return ["\n#\n# {0}\n#".format(self.text)] return [] -def _make_block_conf(block): - """Returns a list of .config strings for a block (list) of items.""" +class Kconfig_Syntax_Error(Exception): + """Exception raised for syntax errors.""" + pass - # Collect the substrings in a list and later use join() instead of += to - # build the final .config contents. With older Python versions, this yields - # linear instead of quadratic complexity. - strings = [] - for item in block: - strings.extend(item._make_conf()) - return strings +class Internal_Error(Exception): + """Exception raised for internal errors.""" + pass + +# +# Public functions +# + +def tri_less(v1, v2): + """Returns True if the tristate v1 is less than the tristate v2, where "n", + "m" and "y" are ordered from lowest to highest.""" + return tri_to_int[v1] < tri_to_int[v2] + +def tri_less_eq(v1, v2): + """Returns True if the tristate v1 is less than or equal to the tristate + v2, where "n", "m" and "y" are ordered from lowest to highest.""" + return tri_to_int[v1] <= tri_to_int[v2] + +def tri_greater(v1, v2): + """Returns True if the tristate v1 is greater than the tristate v2, where + "n", "m" and "y" are ordered from lowest to highest.""" + return tri_to_int[v1] > tri_to_int[v2] + +def tri_greater_eq(v1, v2): + """Returns True if the tristate v1 is greater than or equal to the tristate + v2, where "n", "m" and "y" are ordered from lowest to highest.""" + return tri_to_int[v1] >= tri_to_int[v2] + +# +# Internal classes +# class _Feed(object): @@ -3414,32 +3194,171 @@ class _FileFeed(_Feed): return self.i # -# Misc. public global utility functions +# Internal functions # -def tri_less(v1, v2): - """Returns True if the tristate v1 is less than the tristate v2, where "n", - "m" and "y" are ordered from lowest to highest.""" - return tri_to_int[v1] < tri_to_int[v2] +def _make_and(e1, e2): + """Constructs an AND (&&) expression. Performs trivial simplification. + Nones equate to 'y'. -def tri_less_eq(v1, v2): - """Returns True if the tristate v1 is less than or equal to the tristate - v2, where "n", "m" and "y" are ordered from lowest to highest.""" - return tri_to_int[v1] <= tri_to_int[v2] + Note: returns None if e1 == e2 == None.""" + if e1 == "n" or e2 == "n": + return "n" + if e1 is None or e1 == "y": + return e2 + if e2 is None or e2 == "y": + return e1 -def tri_greater(v1, v2): - """Returns True if the tristate v1 is greater than the tristate v2, where - "n", "m" and "y" are ordered from lowest to highest.""" - return tri_to_int[v1] > tri_to_int[v2] + # Prefer to merge/update argument list if possible instead of creating + # a new AND node -def tri_greater_eq(v1, v2): - """Returns True if the tristate v1 is greater than or equal to the tristate - v2, where "n", "m" and "y" are ordered from lowest to highest.""" - return tri_to_int[v1] >= tri_to_int[v2] + if isinstance(e1, tuple) and e1[0] == AND: + if isinstance(e2, tuple) and e2[0] == AND: + return (AND, e1[1] + e2[1]) + return (AND, e1[1] + [e2]) -# -# Helper functions, mostly related to text processing -# + if isinstance(e2, tuple) and e2[0] == AND: + return (AND, e2[1] + [e1]) + + return (AND, [e1, e2]) + +def _make_or(e1, e2): + """Constructs an OR (||) expression. Performs trivial simplification and + avoids Nones. Nones equate to 'y', which is usually what we want, but needs + to be kept in mind.""" + + # Perform trivial simplification and avoid None's (which + # correspond to y's) + if e1 is None or e2 is None or e1 == "y" or e2 == "y": + return "y" + if e1 == "n": + return e2 + if e2 == "n": + return e1 + + # Prefer to merge/update argument list if possible instead of creating + # a new OR node + + if isinstance(e1, tuple) and e1[0] == OR: + if isinstance(e2, tuple) and e2[0] == OR: + return (OR, e1[1] + e2[1]) + return (OR, e1[1] + [e2]) + + if isinstance(e2, tuple) and e2[0] == OR: + return (OR, e2[1] + [e1]) + + return (OR, [e1, e2]) + +def _get_expr_syms(expr): + """Returns the set() of symbols appearing in expr.""" + res = set() + if expr is None: + return res + + def rec(expr): + if isinstance(expr, Symbol): + res.add(expr) + return + if isinstance(expr, str): + return + + e0 = expr[0] + if e0 == AND or e0 == OR: + for term in expr[1]: + rec(term) + elif e0 == NOT: + rec(expr[1]) + elif e0 == EQUAL or e0 == UNEQUAL: + _, v1, v2 = expr + if isinstance(v1, Symbol): + res.add(v1) + if isinstance(v2, Symbol): + res.add(v2) + else: + _internal_error("Internal error while fetching symbols from an " + "expression with token stream {0}.".format(expr)) + + rec(expr) + return res + +def _str_val(obj): + """Returns the value of obj as a string. If obj is not a string (constant + symbol), it must be a Symbol.""" + return obj if isinstance(obj, str) else obj.get_value() + +def _make_block_conf(block): + """Returns a list of .config strings for a block (list) of items.""" + + # Collect the substrings in a list and later use join() instead of += to + # build the final .config contents. With older Python versions, this yields + # linear instead of quadratic complexity. + strings = [] + for item in block: + strings.extend(item._make_conf()) + return strings + +def _sym_str_string(sym_or_str): + if isinstance(sym_or_str, str): + return '"' + sym_or_str + '"' + return sym_or_str.name + +def _intersperse(lst, op): + """_expr_to_str() helper. Gets the string representation of each expression in lst + and produces a list where op has been inserted between the elements.""" + if lst == []: + return "" + + res = [] + + def handle_sub_expr(expr): + no_parens = isinstance(expr, (str, Symbol)) or \ + expr[0] in (EQUAL, UNEQUAL) or \ + precedence[op] <= precedence[expr[0]] + if not no_parens: + res.append("(") + res.extend(_expr_to_str_rec(expr)) + if not no_parens: + res.append(")") + + op_str = op_to_str[op] + + handle_sub_expr(lst[0]) + for expr in lst[1:]: + res.append(op_str) + handle_sub_expr(expr) + + return res + +def _expr_to_str_rec(expr): + if expr is None: + return [""] + + if isinstance(expr, (Symbol, str)): + return [_sym_str_string(expr)] + + e0 = expr[0] + + if e0 == AND or e0 == OR: + return _intersperse(expr[1], expr[0]) + + if e0 == NOT: + need_parens = not isinstance(expr[1], (str, Symbol)) + + res = ["!"] + if need_parens: + res.append("(") + res.extend(_expr_to_str_rec(expr[1])) + if need_parens: + res.append(")") + return res + + if e0 == EQUAL or e0 == UNEQUAL: + return [_sym_str_string(expr[1]), + op_to_str[expr[0]], + _sym_str_string(expr[2])] + +def _expr_to_str(expr): + return "".join(_expr_to_str_rec(expr)) def _indentation(line): """Returns the length of the line's leading whitespace, treating tab stops @@ -3500,18 +3419,6 @@ def _stderr_msg(msg, filename, linenr): sys.stderr.write("{0}:{1}: ".format(_clean_up_path(filename), linenr)) sys.stderr.write(msg + "\n") -# -# Error handling -# - -class Kconfig_Syntax_Error(Exception): - """Exception raised for syntax errors.""" - pass - -class Internal_Error(Exception): - """Exception raised for internal errors.""" - pass - def _tokenization_error(s, filename, linenr): loc = "" if filename is None else "{0}:{1}: ".format(filename, linenr) raise Kconfig_Syntax_Error("{0}Couldn't tokenize '{1}'" @@ -3528,3 +3435,107 @@ def _internal_error(msg): "\nSorry! You may want to send an email to ulfalizer a.t Google's " \ "email service to tell me about this. Include the message above " \ "and the stack trace and describe what you were doing.") + +# +# Internal global constants +# + +# Tokens +(T_AND, T_OR, T_NOT, + T_OPEN_PAREN, T_CLOSE_PAREN, + T_EQUAL, T_UNEQUAL, + T_MAINMENU, T_MENU, T_ENDMENU, + T_SOURCE, T_CHOICE, T_ENDCHOICE, + T_COMMENT, T_CONFIG, T_MENUCONFIG, + T_HELP, T_IF, T_ENDIF, T_DEPENDS, T_ON, + T_OPTIONAL, T_PROMPT, T_DEFAULT, + T_BOOL, T_TRISTATE, T_HEX, T_INT, T_STRING, + T_DEF_BOOL, T_DEF_TRISTATE, + T_SELECT, T_RANGE, T_OPTION, T_ALLNOCONFIG_Y, T_ENV, + T_DEFCONFIG_LIST, T_MODULES, T_VISIBLE) = range(0, 39) + +# Keyword to token map. Note that the get() method is assigned directly as a +# small optimization. +get_keyword = { "mainmenu" : T_MAINMENU, + "menu" : T_MENU, + "endmenu" : T_ENDMENU, + "endif" : T_ENDIF, + "endchoice" : T_ENDCHOICE, + "source" : T_SOURCE, + "choice" : T_CHOICE, + "config" : T_CONFIG, + "comment" : T_COMMENT, + "menuconfig" : T_MENUCONFIG, + "help" : T_HELP, + "if" : T_IF, + "depends" : T_DEPENDS, + "on" : T_ON, + "optional" : T_OPTIONAL, + "prompt" : T_PROMPT, + "default" : T_DEFAULT, + "bool" : T_BOOL, + "boolean" : T_BOOL, + "tristate" : T_TRISTATE, + "int" : T_INT, + "hex" : T_HEX, + "def_bool" : T_DEF_BOOL, + "def_tristate" : T_DEF_TRISTATE, + "string" : T_STRING, + "select" : T_SELECT, + "range" : T_RANGE, + "option" : T_OPTION, + "allnoconfig_y" : T_ALLNOCONFIG_Y, + "env" : T_ENV, + "defconfig_list" : T_DEFCONFIG_LIST, + "modules" : T_MODULES, + "visible" : T_VISIBLE }.get + +# Strings to use for True and False +bool_str = { False : "false", True : "true" } + +# Tokens after which identifier-like lexemes are treated as strings. T_CHOICE +# is included to avoid symbols being registered for named choices. +string_lex = frozenset((T_BOOL, T_TRISTATE, T_INT, T_HEX, T_STRING, T_CHOICE, + T_PROMPT, T_MENU, T_COMMENT, T_SOURCE, T_MAINMENU)) + +# Matches the initial token on a line; see _tokenize(). +initial_token_re_match = re.compile(r"[^\w]*(\w+)").match + +# Matches an identifier/keyword optionally preceded by whitespace +id_keyword_re_match = re.compile(r"\s*([\w./-]+)").match + +# Regular expressions for parsing .config files +set_re_match = re.compile(r"CONFIG_(\w+)=(.*)").match +unset_re_match = re.compile(r"# CONFIG_(\w+) is not set").match + +# Regular expression for finding $-references to symbols in strings +sym_ref_re_search = re.compile(r"\$[A-Za-z0-9_]+").search + +# Integers representing symbol types +UNKNOWN, BOOL, TRISTATE, STRING, HEX, INT = range(0, 6) + +# Strings to use for types +typename = { UNKNOWN : "unknown", BOOL : "bool", TRISTATE : "tristate", + STRING : "string", HEX : "hex", INT : "int" } + +# Token to type mapping +token_to_type = { T_BOOL : BOOL, T_TRISTATE : TRISTATE, T_STRING : STRING, + T_INT : INT, T_HEX : HEX } + +# Default values for symbols of different types (the value the symbol gets if +# it is not assigned a user value and none of its 'default' clauses kick in) +default_value = { BOOL : "n", TRISTATE : "n", STRING : "", INT : "", HEX : "" } + +# Indicates that no item is selected in a choice statement +NO_SELECTION = 0 + +# Integers representing expression types +AND, OR, NOT, EQUAL, UNEQUAL = range(0, 5) + +# Map from tristate values to integers +tri_to_int = { "n" : 0, "m" : 1, "y" : 2 } + +# Printing-related stuff + +op_to_str = { AND : " && ", OR : " || ", EQUAL : " = ", UNEQUAL : " != " } +precedence = { OR : 0, AND : 1, NOT : 2 } -- cgit v1.2.3