1# Copyright (C) 2014 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15from common.logger import Logger 16from file_format.checker.struct import TestExpression, TestStatement 17 18import os 19import re 20 21def headAndTail(list): 22 return list[0], list[1:] 23 24def splitAtSeparators(expressions): 25 """ Splits a list of TestExpressions at separators. """ 26 splitExpressions = [] 27 wordStart = 0 28 for index, expression in enumerate(expressions): 29 if expression.variant == TestExpression.Variant.Separator: 30 splitExpressions.append(expressions[wordStart:index]) 31 wordStart = index + 1 32 splitExpressions.append(expressions[wordStart:]) 33 return splitExpressions 34 35def getVariable(name, variables, pos): 36 if name in variables: 37 return variables[name] 38 else: 39 Logger.testFailed("Missing definition of variable \"{}\"".format(name), pos, variables) 40 41def setVariable(name, value, variables, pos): 42 if name not in variables: 43 return variables.copyWith(name, value) 44 else: 45 Logger.testFailed("Multiple definitions of variable \"{}\"".format(name), pos, variables) 46 47def matchWords(checkerWord, stringWord, variables, pos): 48 """ Attempts to match a list of TestExpressions against a string. 49 Returns updated variable dictionary if successful and None otherwise. 50 """ 51 for expression in checkerWord: 52 # If `expression` is a variable reference, replace it with the value. 53 if expression.variant == TestExpression.Variant.VarRef: 54 pattern = re.escape(getVariable(expression.name, variables, pos)) 55 else: 56 pattern = expression.text 57 58 # Match the expression's regex pattern against the remainder of the word. 59 # Note: re.match will succeed only if matched from the beginning. 60 match = re.match(pattern, stringWord) 61 if not match: 62 return None 63 64 # If `expression` was a variable definition, set the variable's value. 65 if expression.variant == TestExpression.Variant.VarDef: 66 variables = setVariable(expression.name, stringWord[:match.end()], variables, pos) 67 68 # Move cursor by deleting the matched characters. 69 stringWord = stringWord[match.end():] 70 71 # Make sure the entire word matched, i.e. `stringWord` is empty. 72 if stringWord: 73 return None 74 75 return variables 76 77def MatchLines(checkerLine, stringLine, variables): 78 """ Attempts to match a CHECK line against a string. Returns variable state 79 after the match if successful and None otherwise. 80 """ 81 assert checkerLine.variant != TestStatement.Variant.Eval 82 83 checkerWords = splitAtSeparators(checkerLine.expressions) 84 stringWords = stringLine.split() 85 86 while checkerWords: 87 # Get the next run of TestExpressions which must match one string word. 88 checkerWord, checkerWords = headAndTail(checkerWords) 89 90 # Keep reading words until a match is found. 91 wordMatched = False 92 while stringWords: 93 stringWord, stringWords = headAndTail(stringWords) 94 newVariables = matchWords(checkerWord, stringWord, variables, checkerLine) 95 if newVariables is not None: 96 wordMatched = True 97 variables = newVariables 98 break 99 if not wordMatched: 100 return None 101 102 # All TestExpressions matched. Return new variable state. 103 return variables 104 105def getEvalText(expression, variables, pos): 106 if expression.variant == TestExpression.Variant.PlainText: 107 return expression.text 108 else: 109 assert expression.variant == TestExpression.Variant.VarRef 110 return getVariable(expression.name, variables, pos) 111 112def EvaluateLine(checkerLine, variables): 113 assert checkerLine.isEvalContentStatement() 114 hasIsaFeature = lambda feature: variables["ISA_FEATURES"].get(feature, False) 115 eval_string = "".join(map(lambda expr: getEvalText(expr, variables, checkerLine), 116 checkerLine.expressions)) 117 return eval(eval_string) 118