12ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson#!/usr/bin/python 22ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson# 32ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson# litlint 42ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson# 52ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson# Ensure RUN commands in lit tests are free of common errors. 62ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson# 72ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson# If any errors are detected, litlint returns a nonzero exit code. 82ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson# 92ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 102ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodsonimport optparse 112ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodsonimport re 122ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodsonimport sys 132ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 142ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson# Compile regex once for all files 152ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian HodsonrunRegex = re.compile(r'(?<!-o)(?<!%run) %t\s') 162ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 172ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodsondef LintLine(s): 182ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson """ Validate a line 192ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 202ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson Args: 212ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson s: str, the line to validate 222ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 232ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson Returns: 242ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson Returns an error message and a 1-based column number if an error was 252ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson detected, otherwise (None, None). 262ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson """ 272ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 282ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson # Check that RUN command can be executed with an emulator 292ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson m = runRegex.search(s) 302ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson if m: 312ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson start, end = m.span() 322ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson return ('missing %run before %t', start + 2) 332ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 342ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson # No errors 352ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson return (None, None) 362ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 372ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 382ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodsondef LintFile(p): 392ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson """ Check that each RUN command can be executed with an emulator 402ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 412ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson Args: 422ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson p: str, valid path to a file 432ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 442ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson Returns: 452ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson The number of errors detected. 462ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson """ 472ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson errs = 0 482ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson with open(p, 'r') as f: 492ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson for i, s in enumerate(f.readlines(), start=1): 502ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson msg, col = LintLine(s) 512ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson if msg != None: 522ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson errs += 1 532ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson errorMsg = 'litlint: {}:{}:{}: error: {}.\n{}{}\n' 542ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson arrow = (col-1) * ' ' + '^' 552ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson sys.stderr.write(errorMsg.format(p, i, col, msg, s, arrow)) 562ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson return errs 572ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 582ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 592ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodsonif __name__ == "__main__": 602ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson # Parse args 612ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson parser = optparse.OptionParser() 622ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson parser.add_option('--filter') # ignored 632ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson (options, filenames) = parser.parse_args() 642ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 652ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson # Lint each file 662ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson errs = 0 672ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson for p in filenames: 682ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson errs += LintFile(p) 692ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson 702ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson # If errors, return nonzero 712ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson if errs > 0: 722ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson sys.exit(1) 732ee91b4af4353b9e6a9d591c32fedfc58fd4ef35Ian Hodson