Match compiler: Implement 'verify mode' for Token::Match

Verify mode runs the same ::Match pattern on a token
using the on-the-fly parser and the compiled match parser.
The result is compared and we abort on mismatch.

Already detected an error in our test suite, needs investigation.
This commit is contained in:
Thomas Jarosch 2013-01-07 22:27:57 +01:00
parent 9b51d81e99
commit 9970414a2f
1 changed files with 52 additions and 5 deletions

View File

@ -4,7 +4,8 @@ import re
import glob import glob
class MatchCompiler: class MatchCompiler:
def __init__(self): def __init__(self, verify_mode=False):
self._verifyMode = verify_mode
self._reset() self._reset()
self._selftests() self._selftests()
@ -246,7 +247,39 @@ class MatchCompiler:
return None return None
def _replaceSpecificTokenMatch(self, line, start_pos, end_pos, pattern, tok, varId): def _compileVerifyTokenMatch(self, is_simplematch, verifyNumber, pattern, patternNumber, varId):
more_args = ''
if varId:
more_args = ', const unsigned int varid'
ret = 'static bool match_verify' + str(verifyNumber) + '(const Token *tok'+more_args+') {\n'
origMatchName = 'Match'
if is_simplematch:
origMatchName = 'simpleMatch'
assert(varId == None)
ret += ' bool res_parsed_match = Token::' + origMatchName + '(tok, "' + pattern + '"'
if varId:
ret += ', varid'
ret += ');\n'
ret += ' bool res_compiled_match = match'+str(patternNumber)+'(tok'
if varId:
ret += ', varid'
ret += ');\n'
ret += '\n'
# Don't use assert() here, it's disabled for optimized builds.
# We also need to verify builds in 'release' mode
ret += ' if (res_parsed_match != res_compiled_match)\n'
ret += ' throw InternalError(tok, "Internal error. compiled match returned different result than parsed match");\n'
ret += ' return res_compiled_match;\n'
ret += '}\n'
return ret
def _replaceSpecificTokenMatch(self, is_simplematch, line, start_pos, end_pos, pattern, tok, varId):
more_args = '' more_args = ''
if varId: if varId:
more_args = ',' + varId more_args = ',' + varId
@ -259,12 +292,23 @@ class MatchCompiler:
self._insertMatchFunctionId(patternNumber, pattern, None, varId, False) self._insertMatchFunctionId(patternNumber, pattern, None, varId, False)
self._rawMatchFunctions.append(self._compilePattern(pattern, patternNumber, varId)) self._rawMatchFunctions.append(self._compilePattern(pattern, patternNumber, varId))
return line[:start_pos]+'match'+str(patternNumber)+'('+tok+more_args+')'+line[start_pos+end_pos:] functionName = "match"
if self._verifyMode:
verifyNumber = len(self._rawMatchFunctions) + 1
self._rawMatchFunctions.append(self._compileVerifyTokenMatch(is_simplematch, verifyNumber, pattern, patternNumber, varId))
# inject verify function
functionName = "match_verify"
patternNumber = verifyNumber
return line[:start_pos]+functionName+str(patternNumber)+'('+tok+more_args+')'+line[start_pos+end_pos:]
def _replaceTokenMatch(self, line): def _replaceTokenMatch(self, line):
while True: while True:
is_simplematch = False
pos1 = line.find('Token::Match(') pos1 = line.find('Token::Match(')
if pos1 == -1: if pos1 == -1:
is_simplematch = True
pos1 = line.find('Token::simpleMatch(') pos1 = line.find('Token::simpleMatch(')
if pos1 == -1: if pos1 == -1:
break break
@ -287,7 +331,7 @@ class MatchCompiler:
break # Non-const pattern - bailout break # Non-const pattern - bailout
pattern = res.group(1) pattern = res.group(1)
line = self._replaceSpecificTokenMatch(line, pos1, end_pos, pattern, tok, varId) line = self._replaceSpecificTokenMatch(is_simplematch, line, pos1, end_pos, pattern, tok, varId)
return line return line
@ -431,7 +475,10 @@ class MatchCompiler:
# Main program # Main program
mc = MatchCompiler()
# TODO: Add cmdline switch for verify mode
# Set to 'True' to enable compiled match verification
mc = MatchCompiler(verify_mode=False)
# convert all lib/*.cpp files # convert all lib/*.cpp files
for f in glob.glob('lib/*.cpp'): for f in glob.glob('lib/*.cpp'):