Changes in tools/config.py [093e956:a35b458] in mainline


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • tools/config.py

    r093e956 ra35b458  
    4747PRESETS_DIR = 'defaults'
    4848
    49 class BinaryOp:
    50         def __init__(self, operator, left, right):
    51                 assert operator in ('&', '|', '=', '!=')
    52 
    53                 self._operator = operator
    54                 self._left = left
    55                 self._right = right
    56 
    57         def evaluate(self, config):
    58                 if self._operator == '&':
    59                         return self._left.evaluate(config) and \
    60                             self._right.evaluate(config)
    61                 if self._operator == '|':
    62                         return self._left.evaluate(config) or \
    63                             self._right.evaluate(config)
    64 
    65                 # '=' or '!='
    66                 if not self._left in config:
    67                         config_val = ''
    68                 else:
    69                         config_val = config[self._left]
    70                         if config_val == '*':
    71                                 config_val = 'y'
    72 
    73                 if self._operator == '=':
    74                         return self._right == config_val
    75                 return self._right != config_val
    76 
    77 # Expression parser
    78 class CondParser:
    79         TOKEN_EOE = 0
    80         TOKEN_SPECIAL = 1
    81         TOKEN_STRING = 2
    82 
    83         def __init__(self, text):
    84                 self._text = text
    85 
    86         def parse(self):
    87                 self._position = -1
    88                 self._next_char()
    89                 self._next_token()
    90 
    91                 res = self._parse_expr()
    92                 if self._token_type != self.TOKEN_EOE:
    93                         self._error("Expected end of expression")
    94                 return res
    95 
    96         def _next_char(self):
    97                 self._position += 1
    98                 if self._position >= len(self._text):
    99                         self._char = None
    100                 else:
    101                         self._char = self._text[self._position]
    102                 self._is_special_char = self._char in \
    103                     ('&', '|', '=', '!', '(', ')')
    104 
    105         def _error(self, msg):
    106                 raise RuntimeError("Error parsing expression: %s:\n%s\n%s^" %
    107                     (msg, self._text, " " * self._token_position))
    108 
    109         def _next_token(self):
    110                 self._token_position = self._position
    111 
    112                 # End of expression
    113                 if self._char == None:
    114                         self._token = None
    115                         self._token_type = self.TOKEN_EOE
    116                         return
    117 
    118                 # '&', '|', '=', '!=', '(', ')'
    119                 if self._is_special_char:
    120                         self._token = self._char
    121                         self._next_char()
    122                         if self._token == '!':
    123                                 if self._char != '=':
    124                                         self._error("Expected '='")
    125                                 self._token += self._char
    126                                 self._next_char()
    127                         self._token_type = self.TOKEN_SPECIAL
    128                         return
    129 
    130                 # <var> or <val>
    131                 self._token = ''
    132                 self._token_type = self.TOKEN_STRING
    133                 while True:
    134                         self._token += self._char
    135                         self._next_char()
    136                         if self._is_special_char or self._char == None:
    137                                 break
    138 
    139         def _parse_expr(self):
    140                 """ <expr> ::= <or_expr> ('&' <or_expr>)* """
    141 
    142                 left = self._parse_or_expr()
    143                 while self._token == '&':
    144                         self._next_token()
    145                         left = BinaryOp('&', left, self._parse_or_expr())
    146                 return left
    147 
    148         def _parse_or_expr(self):
    149                 """ <or_expr> ::= <factor> ('|' <factor>)* """
    150 
    151                 left = self._parse_factor()
    152                 while self._token == '|':
    153                         self._next_token()
    154                         left = BinaryOp('|', left, self._parse_factor())
    155                 return left
    156 
    157         def _parse_factor(self):
    158                 """ <factor> ::= <var> <cond> | '(' <expr> ')' """
    159 
    160                 if self._token == '(':
    161                         self._next_token()
    162                         res = self._parse_expr()
    163                         if self._token != ')':
    164                                 self._error("Expected ')'")
    165                         self._next_token()
    166                         return res
    167 
    168                 if self._token_type == self.TOKEN_STRING:
    169                         var = self._token
    170                         self._next_token()
    171                         return self._parse_cond(var)
    172 
    173                 self._error("Expected '(' or <var>")
    174 
    175         def _parse_cond(self, var):
    176                 """ <cond> ::= '=' <val> | '!=' <val> """
    177 
    178                 if self._token not in ('=', '!='):
    179                         self._error("Expected '=' or '!='")
    180 
    181                 oper = self._token
    182                 self._next_token()
    183 
    184                 if self._token_type != self.TOKEN_STRING:
    185                         self._error("Expected <val>")
    186 
    187                 val = self._token
    188                 self._next_token()
    189 
    190                 return BinaryOp(oper, var, val)
    191 
    19249def read_config(fname, config):
    19350        "Read saved values from last configuration run or a preset file"
     
    20259        inf.close()
    20360
     61def check_condition(text, config, rules):
     62        "Check that the condition specified on input line is True (only CNF and DNF is supported)"
     63
     64        ctype = 'cnf'
     65
     66        if (')|' in text) or ('|(' in text):
     67                ctype = 'dnf'
     68
     69        if ctype == 'cnf':
     70                conds = text.split('&')
     71        else:
     72                conds = text.split('|')
     73
     74        for cond in conds:
     75                if cond.startswith('(') and cond.endswith(')'):
     76                        cond = cond[1:-1]
     77
     78                inside = check_inside(cond, config, ctype)
     79
     80                if (ctype == 'cnf') and (not inside):
     81                        return False
     82
     83                if (ctype == 'dnf') and inside:
     84                        return True
     85
     86        if ctype == 'cnf':
     87                return True
     88
     89        return False
     90
     91def check_inside(text, config, ctype):
     92        "Check for condition"
     93
     94        if ctype == 'cnf':
     95                conds = text.split('|')
     96        else:
     97                conds = text.split('&')
     98
     99        for cond in conds:
     100                res = re.match(r'^(.*?)(!?=)(.*)$', cond)
     101                if not res:
     102                        raise RuntimeError("Invalid condition: %s" % cond)
     103
     104                condname = res.group(1)
     105                oper = res.group(2)
     106                condval = res.group(3)
     107
     108                if not condname in config:
     109                        varval = ''
     110                else:
     111                        varval = config[condname]
     112                        if (varval == '*'):
     113                                varval = 'y'
     114
     115                if ctype == 'cnf':
     116                        if (oper == '=') and (condval == varval):
     117                                return True
     118
     119                        if (oper == '!=') and (condval != varval):
     120                                return True
     121                else:
     122                        if (oper == '=') and (condval != varval):
     123                                return False
     124
     125                        if (oper == '!=') and (condval == varval):
     126                                return False
     127
     128        if ctype == 'cnf':
     129                return False
     130
     131        return True
     132
    204133def parse_rules(fname, rules):
    205134        "Parse rules file"
     
    220149
    221150                        cond = res.group(1)
    222                         if cond:
    223                                 cond = CondParser(cond).parse()
    224151                        varname = res.group(2)
    225152                        vartype = res.group(3)
     
    305232                varname, vartype, name, choices, cond = rule
    306233
    307                 if cond and not cond.evaluate(config):
     234                if cond and (not check_condition(cond, config, rules)):
    308235                        continue
    309236
     
    352279
    353280        # First check that this rule would make sense
    354         if cond and not cond.evaluate(config):
    355                 return random_choices(config, rules, start_index + 1)
     281        if cond:
     282                if not check_condition(cond, config, rules):
     283                        return random_choices(config, rules, start_index + 1)
    356284
    357285        # Remember previous choices for backtracking
     
    559487
    560488        for varname, vartype, name, choices, cond in rules:
    561                 if cond and not cond.evaluate(config):
     489                if cond and (not check_condition(cond, config, rules)):
    562490                        continue
    563491
     
    586514        outmk.write('TIMESTAMP_UNIX = %d\n' % timestamp_unix)
    587515        outmc.write('#define TIMESTAMP_UNIX %d\n' % timestamp_unix)
    588         defs += ' "-DTIMESTAMP_UNIX=%d"' % timestamp_unix
     516        defs += ' "-DTIMESTAMP_UNIX=%d"\n' % timestamp_unix
    589517
    590518        outmk.write('TIMESTAMP = %s\n' % timestamp)
    591519        outmc.write('#define TIMESTAMP %s\n' % timestamp)
    592         defs += ' "-DTIMESTAMP=%s"' % timestamp
    593 
    594         outmk.write('%s\n' % defs)
     520        defs += ' "-DTIMESTAMP=%s"\n' % timestamp
     521
     522        outmk.write(defs)
    595523
    596524        outmk.close()
     
    748676                                varname, vartype, name, choices, cond = rule
    749677
    750                                 if cond and not cond.evaluate(config):
     678                                if cond and (not check_condition(cond, config, rules)):
    751679                                        continue
    752680
Note: See TracChangeset for help on using the changeset viewer.