diff options
| author | Ulf Magnusson <ulfalizer@gmail.com> | 2015-06-08 16:13:26 +0200 |
|---|---|---|
| committer | Ulf Magnusson <ulfalizer@gmail.com> | 2015-06-08 16:35:30 +0200 |
| commit | 3cba566b908398b905f7e7229f4dc275db392cc0 (patch) | |
| tree | 797306e37daa097e804e39a5dafbf433164217cc | |
| parent | 707170188fe120c95b16806cbb52c39a4107f792 (diff) | |
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. :)
| -rw-r--r-- | kconfiglib.py | 607 |
1 files changed, 309 insertions, 298 deletions
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,263 +1785,6 @@ class Config(object): if self.print_warnings: _stderr_msg("warning: " + msg, filename, linenr) -# -# Functions and constants related to types, expressions, parsing, evaluation -# and printing -# - -def _make_and(e1, e2): - """Constructs an AND (&&) expression. Performs trivial simplification. - Nones equate to 'y'. - - 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 - - # Prefer to merge/update argument list if possible instead of creating - # a new AND node - - 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]) - - 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 _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)) - -# 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 @@ -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 } |
