Changes in tools/config.py [093e956:a35b458] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
tools/config.py
r093e956 ra35b458 47 47 PRESETS_DIR = 'defaults' 48 48 49 class BinaryOp:50 def __init__(self, operator, left, right):51 assert operator in ('&', '|', '=', '!=')52 53 self._operator = operator54 self._left = left55 self._right = right56 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_val75 return self._right != config_val76 77 # Expression parser78 class CondParser:79 TOKEN_EOE = 080 TOKEN_SPECIAL = 181 TOKEN_STRING = 282 83 def __init__(self, text):84 self._text = text85 86 def parse(self):87 self._position = -188 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 res95 96 def _next_char(self):97 self._position += 198 if self._position >= len(self._text):99 self._char = None100 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._position111 112 # End of expression113 if self._char == None:114 self._token = None115 self._token_type = self.TOKEN_EOE116 return117 118 # '&', '|', '=', '!=', '(', ')'119 if self._is_special_char:120 self._token = self._char121 self._next_char()122 if self._token == '!':123 if self._char != '=':124 self._error("Expected '='")125 self._token += self._char126 self._next_char()127 self._token_type = self.TOKEN_SPECIAL128 return129 130 # <var> or <val>131 self._token = ''132 self._token_type = self.TOKEN_STRING133 while True:134 self._token += self._char135 self._next_char()136 if self._is_special_char or self._char == None:137 break138 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 left147 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 left156 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 res167 168 if self._token_type == self.TOKEN_STRING:169 var = self._token170 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._token182 self._next_token()183 184 if self._token_type != self.TOKEN_STRING:185 self._error("Expected <val>")186 187 val = self._token188 self._next_token()189 190 return BinaryOp(oper, var, val)191 192 49 def read_config(fname, config): 193 50 "Read saved values from last configuration run or a preset file" … … 202 59 inf.close() 203 60 61 def 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 91 def 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 204 133 def parse_rules(fname, rules): 205 134 "Parse rules file" … … 220 149 221 150 cond = res.group(1) 222 if cond:223 cond = CondParser(cond).parse()224 151 varname = res.group(2) 225 152 vartype = res.group(3) … … 305 232 varname, vartype, name, choices, cond = rule 306 233 307 if cond and not cond.evaluate(config):234 if cond and (not check_condition(cond, config, rules)): 308 235 continue 309 236 … … 352 279 353 280 # 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) 356 284 357 285 # Remember previous choices for backtracking … … 559 487 560 488 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)): 562 490 continue 563 491 … … 586 514 outmk.write('TIMESTAMP_UNIX = %d\n' % timestamp_unix) 587 515 outmc.write('#define TIMESTAMP_UNIX %d\n' % timestamp_unix) 588 defs += ' "-DTIMESTAMP_UNIX=%d" ' % timestamp_unix516 defs += ' "-DTIMESTAMP_UNIX=%d"\n' % timestamp_unix 589 517 590 518 outmk.write('TIMESTAMP = %s\n' % timestamp) 591 519 outmc.write('#define TIMESTAMP %s\n' % timestamp) 592 defs += ' "-DTIMESTAMP=%s" ' % timestamp593 594 outmk.write( '%s\n' %defs)520 defs += ' "-DTIMESTAMP=%s"\n' % timestamp 521 522 outmk.write(defs) 595 523 596 524 outmk.close() … … 748 676 varname, vartype, name, choices, cond = rule 749 677 750 if cond and not cond.evaluate(config):678 if cond and (not check_condition(cond, config, rules)): 751 679 continue 752 680
Note:
See TracChangeset
for help on using the changeset viewer.