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, TestAssertion 17 18import re 19 20def headAndTail(list): 21 return list[0], list[1:] 22 23def splitAtSeparators(expressions): 24 """ Splits a list of TestExpressions at separators. """ 25 splitExpressions = [] 26 wordStart = 0 27 for index, expression in enumerate(expressions): 28 if expression.variant == TestExpression.Variant.Separator: 29 splitExpressions.append(expressions[wordStart:index]) 30 wordStart = index + 1 31 splitExpressions.append(expressions[wordStart:]) 32 return splitExpressions 33 34def getVariable(name, variables, pos): 35 if name in variables: 36 return variables[name] 37 else: 38 Logger.testFailed("Missing definition of variable \"{}\"".format(name), pos, variables) 39 40def setVariable(name, value, variables, pos): 41 if name not in variables: 42 return variables.copyWith(name, value) 43 else: 44 Logger.testFailed("Multiple definitions of variable \"{}\"".format(name), pos, variables) 45 46def matchWords(checkerWord, stringWord, variables, pos): 47 """ Attempts to match a list of TestExpressions against a string. 48 Returns updated variable dictionary if successful and None otherwise. 49 """ 50 for expression in checkerWord: 51 # If `expression` is a variable reference, replace it with the value. 52 if expression.variant == TestExpression.Variant.VarRef: 53 pattern = re.escape(getVariable(expression.name, variables, pos)) 54 else: 55 pattern = expression.text 56 57 # Match the expression's regex pattern against the remainder of the word. 58 # Note: re.match will succeed only if matched from the beginning. 59 match = re.match(pattern, stringWord) 60 if not match: 61 return None 62 63 # If `expression` was a variable definition, set the variable's value. 64 if expression.variant == TestExpression.Variant.VarDef: 65 variables = setVariable(expression.name, stringWord[:match.end()], variables, pos) 66 67 # Move cursor by deleting the matched characters. 68 stringWord = stringWord[match.end():] 69 70 # Make sure the entire word matched, i.e. `stringWord` is empty. 71 if stringWord: 72 return None 73 74 return variables 75 76def MatchLines(checkerLine, stringLine, variables): 77 """ Attempts to match a CHECK line against a string. Returns variable state 78 after the match if successful and None otherwise. 79 """ 80 assert checkerLine.variant != TestAssertion.Variant.Eval 81 82 checkerWords = splitAtSeparators(checkerLine.expressions) 83 stringWords = stringLine.split() 84 85 while checkerWords: 86 # Get the next run of TestExpressions which must match one string word. 87 checkerWord, checkerWords = headAndTail(checkerWords) 88 89 # Keep reading words until a match is found. 90 wordMatched = False 91 while stringWords: 92 stringWord, stringWords = headAndTail(stringWords) 93 newVariables = matchWords(checkerWord, stringWord, variables, checkerLine) 94 if newVariables is not None: 95 wordMatched = True 96 variables = newVariables 97 break 98 if not wordMatched: 99 return None 100 101 # All TestExpressions matched. Return new variable state. 102 return variables 103 104def getEvalText(expression, variables, pos): 105 if expression.variant == TestExpression.Variant.PlainText: 106 return expression.text 107 else: 108 assert expression.variant == TestExpression.Variant.VarRef 109 return getVariable(expression.name, variables, pos) 110 111def EvaluateLine(checkerLine, variables): 112 assert checkerLine.variant == TestAssertion.Variant.Eval 113 eval_string = "".join(map(lambda expr: getEvalText(expr, variables, checkerLine), 114 checkerLine.expressions)) 115 return eval(eval_string) 116