Changeset 3b81644b in mainline for tools/config.py
- Timestamp:
- 2019-04-06T11:46:43Z (6 years ago)
- Children:
- 4630eea
- Parents:
- 3daba42e
- git-author:
- Petr Pavlu <setup@…> (2019-03-31 08:24:23)
- git-committer:
- Petr Pavlu <setup@…> (2019-04-06 11:46:43)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
tools/config.py
r3daba42e r3b81644b 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 = 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 49 192 def read_config(fname, config): 50 193 "Read saved values from last configuration run or a preset file" … … 59 202 inf.close() 60 203 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 False82 83 if (ctype == 'dnf') and inside:84 return True85 86 if ctype == 'cnf':87 return True88 89 return False90 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 True118 119 if (oper == '!=') and (condval != varval):120 return True121 else:122 if (oper == '=') and (condval != varval):123 return False124 125 if (oper == '!=') and (condval == varval):126 return False127 128 if ctype == 'cnf':129 return False130 131 return True132 133 204 def parse_rules(fname, rules): 134 205 "Parse rules file" … … 149 220 150 221 cond = res.group(1) 222 if cond: 223 cond = CondParser(cond).parse() 151 224 varname = res.group(2) 152 225 vartype = res.group(3) … … 232 305 varname, vartype, name, choices, cond = rule 233 306 234 if cond and (not check_condition(cond, config, rules)):307 if cond and not cond.evaluate(config): 235 308 continue 236 309 … … 279 352 280 353 # First check that this rule would make sense 281 if cond: 282 if not check_condition(cond, config, rules): 283 return random_choices(config, rules, start_index + 1) 354 if cond and not cond.evaluate(config): 355 return random_choices(config, rules, start_index + 1) 284 356 285 357 # Remember previous choices for backtracking … … 487 559 488 560 for varname, vartype, name, choices, cond in rules: 489 if cond and (not check_condition(cond, config, rules)):561 if cond and not cond.evaluate(config): 490 562 continue 491 563 … … 676 748 varname, vartype, name, choices, cond = rule 677 749 678 if cond and (not check_condition(cond, config, rules)):750 if cond and not cond.evaluate(config): 679 751 continue 680 752
Note:
See TracChangeset
for help on using the changeset viewer.