| 1 | # # @file\r |
| 2 | # This file is used to parse and evaluate range expression in Pcd declaration.\r |
| 3 | #\r |
| 4 | # Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r |
| 5 | # This program and the accompanying materials\r |
| 6 | # are licensed and made available under the terms and conditions of the BSD License\r |
| 7 | # which accompanies this distribution. The full text of the license may be found at\r |
| 8 | # http://opensource.org/licenses/bsd-license.php\r |
| 9 | #\r |
| 10 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r |
| 11 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r |
| 12 | \r |
| 13 | # # Import Modules\r |
| 14 | #\r |
| 15 | from Common.GlobalData import *\r |
| 16 | from CommonDataClass.Exceptions import BadExpression\r |
| 17 | from CommonDataClass.Exceptions import WrnExpression\r |
| 18 | import uuid\r |
| 19 | \r |
| 20 | ERR_STRING_EXPR = 'This operator cannot be used in string expression: [%s].'\r |
| 21 | ERR_SNYTAX = 'Syntax error, the rest of expression cannot be evaluated: [%s].'\r |
| 22 | ERR_MATCH = 'No matching right parenthesis.'\r |
| 23 | ERR_STRING_TOKEN = 'Bad string token: [%s].'\r |
| 24 | ERR_MACRO_TOKEN = 'Bad macro token: [%s].'\r |
| 25 | ERR_EMPTY_TOKEN = 'Empty token is not allowed.'\r |
| 26 | ERR_PCD_RESOLVE = 'PCD token cannot be resolved: [%s].'\r |
| 27 | ERR_VALID_TOKEN = 'No more valid token found from rest of string: [%s].'\r |
| 28 | ERR_EXPR_TYPE = 'Different types found in expression.'\r |
| 29 | ERR_OPERATOR_UNSUPPORT = 'Unsupported operator: [%s]'\r |
| 30 | ERR_REL_NOT_IN = 'Expect "IN" after "not" operator.'\r |
| 31 | WRN_BOOL_EXPR = 'Operand of boolean type cannot be used in arithmetic expression.'\r |
| 32 | WRN_EQCMP_STR_OTHERS = '== Comparison between Operand of string type and Boolean/Number Type always return False.'\r |
| 33 | WRN_NECMP_STR_OTHERS = '!= Comparison between Operand of string type and Boolean/Number Type always return True.'\r |
| 34 | ERR_RELCMP_STR_OTHERS = 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].'\r |
| 35 | ERR_STRING_CMP = 'Unicode string and general string cannot be compared: [%s %s %s]'\r |
| 36 | ERR_ARRAY_TOKEN = 'Bad C array or C format GUID token: [%s].'\r |
| 37 | ERR_ARRAY_ELE = 'This must be HEX value for NList or Array: [%s].'\r |
| 38 | ERR_EMPTY_EXPR = 'Empty expression is not allowed.'\r |
| 39 | ERR_IN_OPERAND = 'Macro after IN operator can only be: $(FAMILY), $(ARCH), $(TOOL_CHAIN_TAG) and $(TARGET).'\r |
| 40 | \r |
| 41 | def MaxOfType(DataType):\r |
| 42 | if DataType == 'UINT8':\r |
| 43 | return int('0xFF', 16)\r |
| 44 | if DataType == 'UINT16':\r |
| 45 | return int('0xFFFF', 16)\r |
| 46 | if DataType == 'UINT32':\r |
| 47 | return int('0xFFFFFFFF', 16)\r |
| 48 | if DataType == 'UINT64':\r |
| 49 | return int('0xFFFFFFFFFFFFFFFF', 16)\r |
| 50 | \r |
| 51 | class RangeObject(object):\r |
| 52 | def __init__(self, start, end, empty = False):\r |
| 53 | \r |
| 54 | if int(start) < int(end):\r |
| 55 | self.start = int(start)\r |
| 56 | self.end = int(end)\r |
| 57 | else:\r |
| 58 | self.start = int(end)\r |
| 59 | self.end = int(start)\r |
| 60 | self.empty = empty\r |
| 61 | \r |
| 62 | class RangeContainer(object):\r |
| 63 | def __init__(self):\r |
| 64 | self.rangelist = []\r |
| 65 | \r |
| 66 | def push(self, RangeObject):\r |
| 67 | self.rangelist.append(RangeObject)\r |
| 68 | self.rangelist = sorted(self.rangelist, key = lambda rangeobj : rangeobj.start)\r |
| 69 | self.merge()\r |
| 70 | \r |
| 71 | def pop(self):\r |
| 72 | for item in self.rangelist:\r |
| 73 | yield item\r |
| 74 | \r |
| 75 | def __clean__(self): \r |
| 76 | newrangelist = []\r |
| 77 | for rangeobj in self.rangelist:\r |
| 78 | if rangeobj.empty == True:\r |
| 79 | continue\r |
| 80 | else:\r |
| 81 | newrangelist.append(rangeobj)\r |
| 82 | self.rangelist = newrangelist \r |
| 83 | def merge(self):\r |
| 84 | self.__clean__()\r |
| 85 | for i in range(0, len(self.rangelist) - 1):\r |
| 86 | if self.rangelist[i + 1].start > self.rangelist[i].end:\r |
| 87 | continue\r |
| 88 | else:\r |
| 89 | self.rangelist[i + 1].start = self.rangelist[i].start\r |
| 90 | self.rangelist[i + 1].end = self.rangelist[i + 1].end > self.rangelist[i].end and self.rangelist[i + 1].end or self.rangelist[i].end \r |
| 91 | self.rangelist[i].empty = True\r |
| 92 | \r |
| 93 | self.__clean__()\r |
| 94 | \r |
| 95 | def dump(self):\r |
| 96 | print "----------------------"\r |
| 97 | rangelist = ""\r |
| 98 | for object in self.rangelist:\r |
| 99 | rangelist = rangelist + "[%d , %d]" % (object.start, object.end)\r |
| 100 | print rangelist\r |
| 101 | \r |
| 102 | \r |
| 103 | class XOROperatorObject(object): \r |
| 104 | def __init__(self): \r |
| 105 | pass\r |
| 106 | def Calculate(self, Operand, DataType, SymbolTable): \r |
| 107 | if type(Operand) == type('') and not Operand.isalnum():\r |
| 108 | Expr = "XOR ..."\r |
| 109 | raise BadExpression(ERR_SNYTAX % Expr)\r |
| 110 | rangeId = str(uuid.uuid1())\r |
| 111 | rangeContainer = RangeContainer()\r |
| 112 | rangeContainer.push(RangeObject(0, int(Operand) - 1))\r |
| 113 | rangeContainer.push(RangeObject(int(Operand) + 1, MaxOfType(DataType)))\r |
| 114 | SymbolTable[rangeId] = rangeContainer\r |
| 115 | return rangeId\r |
| 116 | \r |
| 117 | class LEOperatorObject(object):\r |
| 118 | def __init__(self): \r |
| 119 | pass\r |
| 120 | def Calculate(self, Operand, DataType, SymbolTable): \r |
| 121 | if type(Operand) == type('') and not Operand.isalnum():\r |
| 122 | Expr = "LE ..."\r |
| 123 | raise BadExpression(ERR_SNYTAX % Expr)\r |
| 124 | rangeId1 = str(uuid.uuid1())\r |
| 125 | rangeContainer = RangeContainer()\r |
| 126 | rangeContainer.push(RangeObject(0, int(Operand)))\r |
| 127 | SymbolTable[rangeId1] = rangeContainer\r |
| 128 | return rangeId1\r |
| 129 | class LTOperatorObject(object):\r |
| 130 | def __init__(self): \r |
| 131 | pass\r |
| 132 | def Calculate(self, Operand, DataType, SymbolTable):\r |
| 133 | if type(Operand) == type('') and not Operand.isalnum():\r |
| 134 | Expr = "LT ..." \r |
| 135 | raise BadExpression(ERR_SNYTAX % Expr) \r |
| 136 | rangeId1 = str(uuid.uuid1())\r |
| 137 | rangeContainer = RangeContainer()\r |
| 138 | rangeContainer.push(RangeObject(0, int(Operand) - 1))\r |
| 139 | SymbolTable[rangeId1] = rangeContainer\r |
| 140 | return rangeId1 \r |
| 141 | \r |
| 142 | class GEOperatorObject(object):\r |
| 143 | def __init__(self): \r |
| 144 | pass\r |
| 145 | def Calculate(self, Operand, DataType, SymbolTable): \r |
| 146 | if type(Operand) == type('') and not Operand.isalnum():\r |
| 147 | Expr = "GE ..."\r |
| 148 | raise BadExpression(ERR_SNYTAX % Expr)\r |
| 149 | rangeId1 = str(uuid.uuid1())\r |
| 150 | rangeContainer = RangeContainer()\r |
| 151 | rangeContainer.push(RangeObject(int(Operand), MaxOfType(DataType)))\r |
| 152 | SymbolTable[rangeId1] = rangeContainer\r |
| 153 | return rangeId1 \r |
| 154 | \r |
| 155 | class GTOperatorObject(object):\r |
| 156 | def __init__(self): \r |
| 157 | pass\r |
| 158 | def Calculate(self, Operand, DataType, SymbolTable): \r |
| 159 | if type(Operand) == type('') and not Operand.isalnum():\r |
| 160 | Expr = "GT ..."\r |
| 161 | raise BadExpression(ERR_SNYTAX % Expr)\r |
| 162 | rangeId1 = str(uuid.uuid1())\r |
| 163 | rangeContainer = RangeContainer()\r |
| 164 | rangeContainer.push(RangeObject(int(Operand) + 1, MaxOfType(DataType)))\r |
| 165 | SymbolTable[rangeId1] = rangeContainer\r |
| 166 | return rangeId1 \r |
| 167 | \r |
| 168 | class EQOperatorObject(object):\r |
| 169 | def __init__(self): \r |
| 170 | pass\r |
| 171 | def Calculate(self, Operand, DataType, SymbolTable): \r |
| 172 | if type(Operand) == type('') and not Operand.isalnum():\r |
| 173 | Expr = "EQ ..."\r |
| 174 | raise BadExpression(ERR_SNYTAX % Expr)\r |
| 175 | rangeId1 = str(uuid.uuid1())\r |
| 176 | rangeContainer = RangeContainer()\r |
| 177 | rangeContainer.push(RangeObject(int(Operand) , int(Operand)))\r |
| 178 | SymbolTable[rangeId1] = rangeContainer\r |
| 179 | return rangeId1 \r |
| 180 | \r |
| 181 | def GetOperatorObject(Operator):\r |
| 182 | if Operator == '>':\r |
| 183 | return GTOperatorObject()\r |
| 184 | elif Operator == '>=':\r |
| 185 | return GEOperatorObject()\r |
| 186 | elif Operator == '<':\r |
| 187 | return LTOperatorObject()\r |
| 188 | elif Operator == '<=':\r |
| 189 | return LEOperatorObject()\r |
| 190 | elif Operator == '==':\r |
| 191 | return EQOperatorObject()\r |
| 192 | elif Operator == '^':\r |
| 193 | return XOROperatorObject()\r |
| 194 | else:\r |
| 195 | raise BadExpression("Bad Operator")\r |
| 196 | \r |
| 197 | class RangeExpression(object):\r |
| 198 | # Logical operator mapping\r |
| 199 | LogicalOperators = {\r |
| 200 | '&&' : 'and', '||' : 'or',\r |
| 201 | '!' : 'not', 'AND': 'and',\r |
| 202 | 'OR' : 'or' , 'NOT': 'not',\r |
| 203 | 'XOR': '^' , 'xor': '^',\r |
| 204 | 'EQ' : '==' , 'NE' : '!=',\r |
| 205 | 'GT' : '>' , 'LT' : '<',\r |
| 206 | 'GE' : '>=' , 'LE' : '<=',\r |
| 207 | 'IN' : 'in'\r |
| 208 | }\r |
| 209 | \r |
| 210 | NonLetterOpLst = ['+', '-', '&', '|', '^', '!', '=', '>', '<']\r |
| 211 | \r |
| 212 | PcdPattern = re.compile(r'[_a-zA-Z][0-9A-Za-z_]*\.[_a-zA-Z][0-9A-Za-z_]*$')\r |
| 213 | HexPattern = re.compile(r'0[xX][0-9a-fA-F]+')\r |
| 214 | RegGuidPattern = re.compile(r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}')\r |
| 215 | ExRegGuidPattern = re.compile(r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')\r |
| 216 | \r |
| 217 | RangePattern = re.compile(r'[0-9]+ - [0-9]+')\r |
| 218 | \r |
| 219 | def preProcessRangeExpr(self, expr):\r |
| 220 | # convert hex to int\r |
| 221 | # convert interval to object index. ex. 1 - 10 to a GUID\r |
| 222 | expr = expr.strip()\r |
| 223 | NumberDict = {}\r |
| 224 | for HexNumber in self.HexPattern.findall(expr):\r |
| 225 | Number = str(int(HexNumber, 16))\r |
| 226 | NumberDict[HexNumber] = Number\r |
| 227 | for HexNum in NumberDict:\r |
| 228 | expr = expr.replace(HexNum, NumberDict[HexNum])\r |
| 229 | \r |
| 230 | rangedict = {} \r |
| 231 | for validrange in self.RangePattern.findall(expr):\r |
| 232 | start, end = validrange.split(" - ")\r |
| 233 | start = start.strip()\r |
| 234 | end = end.strip()\r |
| 235 | rangeid = str(uuid.uuid1())\r |
| 236 | rangeContainer = RangeContainer()\r |
| 237 | rangeContainer.push(RangeObject(start, end))\r |
| 238 | self.operanddict[str(rangeid)] = rangeContainer\r |
| 239 | rangedict[validrange] = str(rangeid)\r |
| 240 | \r |
| 241 | for validrange in rangedict:\r |
| 242 | expr = expr.replace(validrange, rangedict[validrange])\r |
| 243 | \r |
| 244 | self._Expr = expr \r |
| 245 | return expr\r |
| 246 | \r |
| 247 | \r |
| 248 | def EvalRange(self, Operator, Oprand):\r |
| 249 | \r |
| 250 | operatorobj = GetOperatorObject(Operator)\r |
| 251 | return operatorobj.Calculate(Oprand, self.PcdDataType, self.operanddict)\r |
| 252 | \r |
| 253 | def Rangeintersection(self, Oprand1, Oprand2):\r |
| 254 | rangeContainer1 = self.operanddict[Oprand1]\r |
| 255 | rangeContainer2 = self.operanddict[Oprand2]\r |
| 256 | rangeContainer = RangeContainer()\r |
| 257 | for range1 in rangeContainer1.pop():\r |
| 258 | for range2 in rangeContainer2.pop():\r |
| 259 | start1 = range1.start\r |
| 260 | end1 = range1.end\r |
| 261 | start2 = range2.start\r |
| 262 | end2 = range2.end\r |
| 263 | if start1 >= start2:\r |
| 264 | start1, start2 = start2, start1\r |
| 265 | end1, end2 = end2, end1\r |
| 266 | if range1.empty:\r |
| 267 | rangeid = str(uuid.uuid1())\r |
| 268 | rangeContainer.push(RangeObject(0, 0, True))\r |
| 269 | if end1 < start2:\r |
| 270 | rangeid = str(uuid.uuid1())\r |
| 271 | rangeContainer.push(RangeObject(0, 0, True))\r |
| 272 | elif end1 == start2:\r |
| 273 | rangeid = str(uuid.uuid1())\r |
| 274 | rangeContainer.push(RangeObject(end1, end1))\r |
| 275 | elif end1 <= end2 and end1 > start2:\r |
| 276 | rangeid = str(uuid.uuid1())\r |
| 277 | rangeContainer.push(RangeObject(start2, end1))\r |
| 278 | elif end1 >= end2:\r |
| 279 | rangeid = str(uuid.uuid1())\r |
| 280 | rangeContainer.push(RangeObject(start2, end2))\r |
| 281 | \r |
| 282 | self.operanddict[rangeid] = rangeContainer\r |
| 283 | # rangeContainer.dump()\r |
| 284 | return rangeid\r |
| 285 | \r |
| 286 | def Rangecollections(self, Oprand1, Oprand2):\r |
| 287 | \r |
| 288 | rangeContainer1 = self.operanddict[Oprand1]\r |
| 289 | rangeContainer2 = self.operanddict[Oprand2]\r |
| 290 | rangeContainer = RangeContainer()\r |
| 291 | \r |
| 292 | for rangeobj in rangeContainer2.pop():\r |
| 293 | rangeContainer.push(rangeobj)\r |
| 294 | for rangeobj in rangeContainer1.pop():\r |
| 295 | rangeContainer.push(rangeobj)\r |
| 296 | \r |
| 297 | rangeid = str(uuid.uuid1())\r |
| 298 | self.operanddict[rangeid] = rangeContainer\r |
| 299 | \r |
| 300 | # rangeContainer.dump()\r |
| 301 | return rangeid\r |
| 302 | \r |
| 303 | \r |
| 304 | def NegtiveRange(self, Oprand1):\r |
| 305 | rangeContainer1 = self.operanddict[Oprand1]\r |
| 306 | \r |
| 307 | \r |
| 308 | rangeids = []\r |
| 309 | \r |
| 310 | for rangeobj in rangeContainer1.pop():\r |
| 311 | rangeContainer = RangeContainer()\r |
| 312 | rangeid = str(uuid.uuid1())\r |
| 313 | if rangeobj.empty:\r |
| 314 | rangeContainer.push(RangeObject(0, MaxOfType(self.PcdDataType)))\r |
| 315 | else:\r |
| 316 | if rangeobj.start > 0:\r |
| 317 | rangeContainer.push(RangeObject(0, rangeobj.start - 1))\r |
| 318 | if rangeobj.end < MaxOfType(self.PcdDataType):\r |
| 319 | rangeContainer.push(RangeObject(rangeobj.end + 1, MaxOfType(self.PcdDataType)))\r |
| 320 | self.operanddict[rangeid] = rangeContainer\r |
| 321 | rangeids.append(rangeid)\r |
| 322 | \r |
| 323 | if len(rangeids) == 0:\r |
| 324 | rangeContainer = RangeContainer()\r |
| 325 | rangeContainer.push(RangeObject(0, MaxOfType(self.PcdDataType)))\r |
| 326 | rangeid = str(uuid.uuid1())\r |
| 327 | self.operanddict[rangeid] = rangeContainer\r |
| 328 | return rangeid\r |
| 329 | \r |
| 330 | if len(rangeids) == 1:\r |
| 331 | return rangeids[0]\r |
| 332 | \r |
| 333 | re = self.Rangeintersection(rangeids[0], rangeids[1])\r |
| 334 | for i in range(2, len(rangeids)):\r |
| 335 | re = self.Rangeintersection(re, rangeids[i])\r |
| 336 | \r |
| 337 | rangeid2 = str(uuid.uuid1())\r |
| 338 | self.operanddict[rangeid2] = self.operanddict[re]\r |
| 339 | return rangeid2\r |
| 340 | \r |
| 341 | def Eval(self, Operator, Oprand1, Oprand2 = None):\r |
| 342 | \r |
| 343 | if Operator in ["!", "NOT", "not"]:\r |
| 344 | if not self.RegGuidPattern.match(Oprand1.strip()):\r |
| 345 | raise BadExpression(ERR_STRING_EXPR % Operator)\r |
| 346 | return self.NegtiveRange(Oprand1)\r |
| 347 | else:\r |
| 348 | if Operator in ["==", ">=", "<=", ">", "<", '^']:\r |
| 349 | return self.EvalRange(Operator, Oprand1)\r |
| 350 | elif Operator == 'and' :\r |
| 351 | if not self.ExRegGuidPattern.match(Oprand1.strip()) or not self.ExRegGuidPattern.match(Oprand2.strip()):\r |
| 352 | raise BadExpression(ERR_STRING_EXPR % Operator)\r |
| 353 | return self.Rangeintersection(Oprand1, Oprand2) \r |
| 354 | elif Operator == 'or':\r |
| 355 | if not self.ExRegGuidPattern.match(Oprand1.strip()) or not self.ExRegGuidPattern.match(Oprand2.strip()):\r |
| 356 | raise BadExpression(ERR_STRING_EXPR % Operator)\r |
| 357 | return self.Rangecollections(Oprand1, Oprand2)\r |
| 358 | else:\r |
| 359 | raise BadExpression(ERR_STRING_EXPR % Operator)\r |
| 360 | \r |
| 361 | \r |
| 362 | def __init__(self, Expression, PcdDataType, SymbolTable = {}):\r |
| 363 | self._NoProcess = False\r |
| 364 | if type(Expression) != type(''):\r |
| 365 | self._Expr = Expression\r |
| 366 | self._NoProcess = True\r |
| 367 | return\r |
| 368 | \r |
| 369 | self._Expr = Expression.strip()\r |
| 370 | \r |
| 371 | if not self._Expr.strip():\r |
| 372 | raise BadExpression(ERR_EMPTY_EXPR)\r |
| 373 | \r |
| 374 | #\r |
| 375 | # The symbol table including PCD and macro mapping\r |
| 376 | #\r |
| 377 | self._Symb = SymbolTable\r |
| 378 | self._Symb.update(self.LogicalOperators)\r |
| 379 | self._Idx = 0\r |
| 380 | self._Len = len(self._Expr)\r |
| 381 | self._Token = ''\r |
| 382 | self._WarnExcept = None\r |
| 383 | \r |
| 384 | \r |
| 385 | # Literal token without any conversion\r |
| 386 | self._LiteralToken = ''\r |
| 387 | \r |
| 388 | # store the operand object\r |
| 389 | self.operanddict = {}\r |
| 390 | # The Pcd max value depends on PcdDataType\r |
| 391 | self.PcdDataType = PcdDataType\r |
| 392 | \r |
| 393 | # Public entry for this class\r |
| 394 | # @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression\r |
| 395 | # True : return the evaluated str(value), used for PCD value\r |
| 396 | #\r |
| 397 | # @return: True or False if RealValue is False\r |
| 398 | # Evaluated value of string format if RealValue is True\r |
| 399 | #\r |
| 400 | def __call__(self, RealValue = False, Depth = 0):\r |
| 401 | if self._NoProcess:\r |
| 402 | return self._Expr\r |
| 403 | \r |
| 404 | self._Depth = Depth\r |
| 405 | \r |
| 406 | self._Expr = self._Expr.strip()\r |
| 407 | \r |
| 408 | self.preProcessRangeExpr(self._Expr)\r |
| 409 | \r |
| 410 | # check if the expression does not need to evaluate\r |
| 411 | if RealValue and Depth == 0:\r |
| 412 | self._Token = self._Expr\r |
| 413 | if self.ExRegGuidPattern.match(self._Expr):\r |
| 414 | return [self.operanddict[self._Expr] ]\r |
| 415 | \r |
| 416 | self._Idx = 0\r |
| 417 | self._Token = ''\r |
| 418 | \r |
| 419 | Val = self._OrExpr()\r |
| 420 | RealVal = Val\r |
| 421 | \r |
| 422 | RangeIdList = RealVal.split("or")\r |
| 423 | RangeList = []\r |
| 424 | for rangeid in RangeIdList:\r |
| 425 | RangeList.append(self.operanddict[rangeid.strip()])\r |
| 426 | \r |
| 427 | return RangeList\r |
| 428 | \r |
| 429 | # Template function to parse binary operators which have same precedence\r |
| 430 | # Expr [Operator Expr]*\r |
| 431 | def _ExprFuncTemplate(self, EvalFunc, OpLst):\r |
| 432 | Val = EvalFunc()\r |
| 433 | while self._IsOperator(OpLst):\r |
| 434 | Op = self._Token\r |
| 435 | try:\r |
| 436 | Val = self.Eval(Op, Val, EvalFunc())\r |
| 437 | except WrnExpression, Warn:\r |
| 438 | self._WarnExcept = Warn\r |
| 439 | Val = Warn.result\r |
| 440 | return Val\r |
| 441 | \r |
| 442 | # A [|| B]*\r |
| 443 | def _OrExpr(self):\r |
| 444 | return self._ExprFuncTemplate(self._AndExpr, ["OR", "or"])\r |
| 445 | \r |
| 446 | # A [&& B]*\r |
| 447 | def _AndExpr(self):\r |
| 448 | return self._ExprFuncTemplate(self._NeExpr, ["AND", "and"])\r |
| 449 | \r |
| 450 | def _NeExpr(self):\r |
| 451 | Val = self._RelExpr()\r |
| 452 | while self._IsOperator([ "!=", "NOT", "not"]):\r |
| 453 | Op = self._Token\r |
| 454 | if Op in ["!", "NOT", "not"]:\r |
| 455 | if not self._IsOperator(["IN", "in"]):\r |
| 456 | raise BadExpression(ERR_REL_NOT_IN)\r |
| 457 | Op += ' ' + self._Token\r |
| 458 | try:\r |
| 459 | Val = self.Eval(Op, Val, self._RelExpr())\r |
| 460 | except WrnExpression, Warn:\r |
| 461 | self._WarnExcept = Warn\r |
| 462 | Val = Warn.result\r |
| 463 | return Val\r |
| 464 | \r |
| 465 | # [!]*A\r |
| 466 | def _RelExpr(self):\r |
| 467 | if self._IsOperator(["NOT" , "LE", "GE", "LT", "GT", "EQ", "XOR"]):\r |
| 468 | Token = self._Token\r |
| 469 | Val = self._NeExpr()\r |
| 470 | try:\r |
| 471 | return self.Eval(Token, Val)\r |
| 472 | except WrnExpression, Warn:\r |
| 473 | self._WarnExcept = Warn\r |
| 474 | return Warn.result\r |
| 475 | return self._IdenExpr()\r |
| 476 | \r |
| 477 | # Parse identifier or encapsulated expression\r |
| 478 | def _IdenExpr(self):\r |
| 479 | Tk = self._GetToken()\r |
| 480 | if Tk == '(':\r |
| 481 | Val = self._OrExpr()\r |
| 482 | try:\r |
| 483 | # _GetToken may also raise BadExpression\r |
| 484 | if self._GetToken() != ')':\r |
| 485 | raise BadExpression(ERR_MATCH)\r |
| 486 | except BadExpression:\r |
| 487 | raise BadExpression(ERR_MATCH)\r |
| 488 | return Val\r |
| 489 | return Tk\r |
| 490 | \r |
| 491 | # Skip whitespace or tab\r |
| 492 | def __SkipWS(self):\r |
| 493 | for Char in self._Expr[self._Idx:]:\r |
| 494 | if Char not in ' \t':\r |
| 495 | break\r |
| 496 | self._Idx += 1\r |
| 497 | \r |
| 498 | # Try to convert string to number\r |
| 499 | def __IsNumberToken(self):\r |
| 500 | Radix = 10\r |
| 501 | if self._Token.lower()[0:2] == '0x' and len(self._Token) > 2:\r |
| 502 | Radix = 16\r |
| 503 | try:\r |
| 504 | self._Token = int(self._Token, Radix)\r |
| 505 | return True\r |
| 506 | except ValueError:\r |
| 507 | return False\r |
| 508 | except TypeError:\r |
| 509 | return False\r |
| 510 | \r |
| 511 | # Parse array: {...}\r |
| 512 | def __GetArray(self):\r |
| 513 | Token = '{'\r |
| 514 | self._Idx += 1\r |
| 515 | self.__GetNList(True)\r |
| 516 | Token += self._LiteralToken\r |
| 517 | if self._Idx >= self._Len or self._Expr[self._Idx] != '}':\r |
| 518 | raise BadExpression(ERR_ARRAY_TOKEN % Token)\r |
| 519 | Token += '}'\r |
| 520 | \r |
| 521 | # All whitespace and tabs in array are already stripped.\r |
| 522 | IsArray = IsGuid = False\r |
| 523 | if len(Token.split(',')) == 11 and len(Token.split(',{')) == 2 \\r |
| 524 | and len(Token.split('},')) == 1:\r |
| 525 | HexLen = [11, 6, 6, 5, 4, 4, 4, 4, 4, 4, 6]\r |
| 526 | HexList = Token.split(',')\r |
| 527 | if HexList[3].startswith('{') and \\r |
| 528 | not [Index for Index, Hex in enumerate(HexList) if len(Hex) > HexLen[Index]]:\r |
| 529 | IsGuid = True\r |
| 530 | if Token.lstrip('{').rstrip('}').find('{') == -1:\r |
| 531 | if not [Hex for Hex in Token.lstrip('{').rstrip('}').split(',') if len(Hex) > 4]:\r |
| 532 | IsArray = True\r |
| 533 | if not IsArray and not IsGuid:\r |
| 534 | raise BadExpression(ERR_ARRAY_TOKEN % Token)\r |
| 535 | self._Idx += 1\r |
| 536 | self._Token = self._LiteralToken = Token\r |
| 537 | return self._Token\r |
| 538 | \r |
| 539 | # Parse string, the format must be: "..."\r |
| 540 | def __GetString(self):\r |
| 541 | Idx = self._Idx\r |
| 542 | \r |
| 543 | # Skip left quote\r |
| 544 | self._Idx += 1\r |
| 545 | \r |
| 546 | # Replace escape \\\", \"\r |
| 547 | Expr = self._Expr[self._Idx:].replace('\\\\', '//').replace('\\\"', '\\\'')\r |
| 548 | for Ch in Expr:\r |
| 549 | self._Idx += 1\r |
| 550 | if Ch == '"':\r |
| 551 | break\r |
| 552 | self._Token = self._LiteralToken = self._Expr[Idx:self._Idx]\r |
| 553 | if not self._Token.endswith('"'):\r |
| 554 | raise BadExpression(ERR_STRING_TOKEN % self._Token)\r |
| 555 | self._Token = self._Token[1:-1]\r |
| 556 | return self._Token\r |
| 557 | \r |
| 558 | # Get token that is comprised by alphanumeric, underscore or dot(used by PCD)\r |
| 559 | # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)\r |
| 560 | def __GetIdToken(self, IsAlphaOp = False):\r |
| 561 | IdToken = ''\r |
| 562 | for Ch in self._Expr[self._Idx:]:\r |
| 563 | if not self.__IsIdChar(Ch):\r |
| 564 | break\r |
| 565 | self._Idx += 1\r |
| 566 | IdToken += Ch\r |
| 567 | \r |
| 568 | self._Token = self._LiteralToken = IdToken\r |
| 569 | if not IsAlphaOp:\r |
| 570 | self.__ResolveToken()\r |
| 571 | return self._Token\r |
| 572 | \r |
| 573 | # Try to resolve token\r |
| 574 | def __ResolveToken(self):\r |
| 575 | if not self._Token:\r |
| 576 | raise BadExpression(ERR_EMPTY_TOKEN)\r |
| 577 | \r |
| 578 | # PCD token\r |
| 579 | if self.PcdPattern.match(self._Token):\r |
| 580 | if self._Token not in self._Symb:\r |
| 581 | Ex = BadExpression(ERR_PCD_RESOLVE % self._Token)\r |
| 582 | Ex.Pcd = self._Token\r |
| 583 | raise Ex\r |
| 584 | self._Token = RangeExpression(self._Symb[self._Token], self._Symb)(True, self._Depth + 1)\r |
| 585 | if type(self._Token) != type(''):\r |
| 586 | self._LiteralToken = hex(self._Token)\r |
| 587 | return\r |
| 588 | \r |
| 589 | if self._Token.startswith('"'):\r |
| 590 | self._Token = self._Token[1:-1]\r |
| 591 | elif self._Token in ["FALSE", "false", "False"]:\r |
| 592 | self._Token = False\r |
| 593 | elif self._Token in ["TRUE", "true", "True"]:\r |
| 594 | self._Token = True\r |
| 595 | else:\r |
| 596 | self.__IsNumberToken()\r |
| 597 | \r |
| 598 | def __GetNList(self, InArray = False):\r |
| 599 | self._GetSingleToken()\r |
| 600 | if not self.__IsHexLiteral():\r |
| 601 | if InArray:\r |
| 602 | raise BadExpression(ERR_ARRAY_ELE % self._Token)\r |
| 603 | return self._Token\r |
| 604 | \r |
| 605 | self.__SkipWS()\r |
| 606 | Expr = self._Expr[self._Idx:]\r |
| 607 | if not Expr.startswith(','):\r |
| 608 | return self._Token\r |
| 609 | \r |
| 610 | NList = self._LiteralToken\r |
| 611 | while Expr.startswith(','):\r |
| 612 | NList += ','\r |
| 613 | self._Idx += 1\r |
| 614 | self.__SkipWS()\r |
| 615 | self._GetSingleToken()\r |
| 616 | if not self.__IsHexLiteral():\r |
| 617 | raise BadExpression(ERR_ARRAY_ELE % self._Token)\r |
| 618 | NList += self._LiteralToken\r |
| 619 | self.__SkipWS()\r |
| 620 | Expr = self._Expr[self._Idx:]\r |
| 621 | self._Token = self._LiteralToken = NList\r |
| 622 | return self._Token\r |
| 623 | \r |
| 624 | def __IsHexLiteral(self):\r |
| 625 | if self._LiteralToken.startswith('{') and \\r |
| 626 | self._LiteralToken.endswith('}'):\r |
| 627 | return True\r |
| 628 | \r |
| 629 | if self.HexPattern.match(self._LiteralToken):\r |
| 630 | Token = self._LiteralToken[2:]\r |
| 631 | Token = Token.lstrip('0')\r |
| 632 | if not Token:\r |
| 633 | self._LiteralToken = '0x0'\r |
| 634 | else:\r |
| 635 | self._LiteralToken = '0x' + Token.lower()\r |
| 636 | return True\r |
| 637 | return False\r |
| 638 | \r |
| 639 | def _GetToken(self):\r |
| 640 | return self.__GetNList()\r |
| 641 | \r |
| 642 | @staticmethod\r |
| 643 | def __IsIdChar(Ch):\r |
| 644 | return Ch in '._/:' or Ch.isalnum()\r |
| 645 | \r |
| 646 | # Parse operand\r |
| 647 | def _GetSingleToken(self):\r |
| 648 | self.__SkipWS()\r |
| 649 | Expr = self._Expr[self._Idx:]\r |
| 650 | if Expr.startswith('L"'):\r |
| 651 | # Skip L\r |
| 652 | self._Idx += 1\r |
| 653 | UStr = self.__GetString()\r |
| 654 | self._Token = 'L"' + UStr + '"'\r |
| 655 | return self._Token\r |
| 656 | \r |
| 657 | self._Token = ''\r |
| 658 | if Expr:\r |
| 659 | Ch = Expr[0]\r |
| 660 | Match = self.RegGuidPattern.match(Expr)\r |
| 661 | if Match and not Expr[Match.end():Match.end() + 1].isalnum() \\r |
| 662 | and Expr[Match.end():Match.end() + 1] != '_':\r |
| 663 | self._Idx += Match.end()\r |
| 664 | self._Token = Expr[0:Match.end()]\r |
| 665 | return self._Token\r |
| 666 | elif self.__IsIdChar(Ch):\r |
| 667 | return self.__GetIdToken()\r |
| 668 | elif Ch == '(' or Ch == ')':\r |
| 669 | self._Idx += 1\r |
| 670 | self._Token = Ch\r |
| 671 | return self._Token\r |
| 672 | \r |
| 673 | raise BadExpression(ERR_VALID_TOKEN % Expr)\r |
| 674 | \r |
| 675 | # Parse operator\r |
| 676 | def _GetOperator(self):\r |
| 677 | self.__SkipWS()\r |
| 678 | LegalOpLst = ['&&', '||', '!=', '==', '>=', '<='] + self.NonLetterOpLst\r |
| 679 | \r |
| 680 | self._Token = ''\r |
| 681 | Expr = self._Expr[self._Idx:]\r |
| 682 | \r |
| 683 | # Reach end of expression\r |
| 684 | if not Expr:\r |
| 685 | return ''\r |
| 686 | \r |
| 687 | # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not\r |
| 688 | if Expr[0].isalpha():\r |
| 689 | return self.__GetIdToken(True)\r |
| 690 | \r |
| 691 | # Start to get regular operator: +, -, <, > ...\r |
| 692 | if Expr[0] not in self.NonLetterOpLst:\r |
| 693 | return ''\r |
| 694 | \r |
| 695 | OpToken = ''\r |
| 696 | for Ch in Expr:\r |
| 697 | if Ch in self.NonLetterOpLst:\r |
| 698 | if '!' == Ch and OpToken:\r |
| 699 | break\r |
| 700 | self._Idx += 1\r |
| 701 | OpToken += Ch\r |
| 702 | else:\r |
| 703 | break\r |
| 704 | \r |
| 705 | if OpToken not in LegalOpLst:\r |
| 706 | raise BadExpression(ERR_OPERATOR_UNSUPPORT % OpToken)\r |
| 707 | self._Token = OpToken\r |
| 708 | return OpToken\r |
| 709 | \r |
| 710 | # Check if current token matches the operators given from OpList\r |
| 711 | def _IsOperator(self, OpList):\r |
| 712 | Idx = self._Idx\r |
| 713 | self._GetOperator()\r |
| 714 | if self._Token in OpList:\r |
| 715 | if self._Token in self.LogicalOperators:\r |
| 716 | self._Token = self.LogicalOperators[self._Token]\r |
| 717 | return True\r |
| 718 | self._Idx = Idx\r |
| 719 | return False\r |
| 720 | \r |
| 721 | \r |
| 722 | \r |
| 723 | \r |
| 724 | \r |
| 725 | \r |
| 726 | \r |
| 727 | \r |
| 728 | \r |
| 729 | \r |
| 730 | # UTRangeList()\r |