12da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#!/usr/bin/env python 22da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 32da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Copyright 2008 The Closure Linter Authors. All Rights Reserved. 42da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 52da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Licensed under the Apache License, Version 2.0 (the "License"); 62da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# you may not use this file except in compliance with the License. 72da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# You may obtain a copy of the License at 82da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 92da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# http://www.apache.org/licenses/LICENSE-2.0 102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Unless required by applicable law or agreed to in writing, software 122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# distributed under the License is distributed on an "AS-IS" BASIS, 132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# See the License for the specific language governing permissions and 152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# limitations under the License. 162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis"""Base classes for writing checkers that operate on tokens.""" 182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis__author__ = ('robbyw@google.com (Robert Walker)', 202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'ajp@google.com (Andy Perelson)', 212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'jacobr@google.com (Jacob Richman)') 222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 232da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport StringIO 242da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport traceback 252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 262da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport gflags as flags 272da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom closure_linter import ecmametadatapass 282da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom closure_linter import errorrules 292da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom closure_linter import errors 302da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom closure_linter import javascripttokenizer 312da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom closure_linter.common import error 322da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom closure_linter.common import htmlutil 332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 342da489cd246702bee5938545b18a6f710ed214bcJamie GennisFLAGS = flags.FLAGS 352da489cd246702bee5938545b18a6f710ed214bcJamie Gennisflags.DEFINE_boolean('debug_tokens', False, 362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'Whether to print all tokens for debugging.') 372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 382da489cd246702bee5938545b18a6f710ed214bcJamie Gennisflags.DEFINE_boolean('error_trace', False, 392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'Whether to show error exceptions.') 402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 422da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass LintRulesBase(object): 432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Base class for all classes defining the lint rules for a language.""" 442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self): 462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.__checker = None 472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Initialize(self, checker, limited_doc_checks, is_html): 492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Initializes to prepare to check a file. 502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis checker: Class to report errors to. 532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis limited_doc_checks: Whether doc checking is relaxed for this file. 542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_html: Whether the file is an HTML file with extracted contents. 552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.__checker = checker 572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._limited_doc_checks = limited_doc_checks 582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._is_html = is_html 592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _HandleError(self, code, message, token, position=None, 612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis fix_data=None): 622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Call the HandleError function for the checker we are associated with.""" 632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if errorrules.ShouldReportError(code): 642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.__checker.HandleError(code, message, token, position, fix_data) 652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _SetLimitedDocChecks(self, limited_doc_checks): 672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Sets whether doc checking is relaxed for this file. 682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis limited_doc_checks: Whether doc checking is relaxed for this file. 712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._limited_doc_checks = limited_doc_checks 732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def CheckToken(self, token, parser_state): 752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Checks a token, given the current parser_state, for warnings and errors. 762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token: The current token under consideration. 792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis parser_state: Object that indicates the parser state in the page. 802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Raises: 822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis TypeError: If not overridden. 832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis raise TypeError('Abstract method CheckToken not implemented') 852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Finalize(self, parser_state, tokenizer_mode): 872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Perform all checks that need to occur after all lines are processed. 882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis parser_state: State of the parser after parsing all tokens 912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis tokenizer_mode: Mode of the tokenizer after parsing the entire page 922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Raises: 942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis TypeError: If not overridden. 952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis raise TypeError('Abstract method Finalize not implemented') 972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 992da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass CheckerBase(object): 1002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """This class handles checking a LintRules object against a file.""" 1012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self, error_handler, lint_rules, state_tracker, 1032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis limited_doc_files=None, metadata_pass=None): 1042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Initialize a checker object. 1052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 1072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis error_handler: Object that handles errors. 1082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis lint_rules: LintRules object defining lint errors given a token 1092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis and state_tracker object. 1102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis state_tracker: Object that tracks the current state in the token stream. 1112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis limited_doc_files: List of filenames that are not required to have 1122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis documentation comments. 1132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis metadata_pass: Object that builds metadata about the token stream. 1142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 1152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._error_handler = error_handler 1162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._lint_rules = lint_rules 1172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._state_tracker = state_tracker 1182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._metadata_pass = metadata_pass 1192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._limited_doc_files = limited_doc_files 1202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # TODO(user): Factor out. A checker does not need to know about the 1222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # tokenizer, only the token stream. 1232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._tokenizer = javascripttokenizer.JavaScriptTokenizer() 1242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._has_errors = False 1262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def HandleError(self, code, message, token, position=None, 1282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis fix_data=None): 1292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Prints out the given error message including a line number. 1302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 1322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis code: The error code. 1332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis message: The error to print. 1342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token: The token where the error occurred, or None if it was a file-wide 1352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis issue. 1362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis position: The position of the error, defaults to None. 1372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis fix_data: Metadata used for fixing the error. 1382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 1392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._has_errors = True 1402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._error_handler.HandleError( 1412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis error.Error(code, message, token, position, fix_data)) 1422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def HasErrors(self): 1442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns true if the style checker has found any errors. 1452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 1472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if the style checker has found any errors. 1482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 1492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._has_errors 1502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Check(self, filename, source=None): 1522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Checks the file, printing warnings and errors as they are found. 1532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 1552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis filename: The name of the file to check. 1562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis source: Optional. The contents of the file. Can be either a string or 1572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis file-like object. If omitted, contents will be read from disk from 1582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis the given filename. 1592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 1602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if source is None: 1622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis try: 1632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis f = open(filename) 1642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis except IOError: 1652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._error_handler.HandleFile(filename, None) 1662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.HandleError(errors.FILE_NOT_FOUND, 'File not found', None) 1672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._error_handler.FinishFile() 1682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return 1692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 1702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if type(source) in [str, unicode]: 1712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis f = StringIO.StringIO(source) 1722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 1732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis f = source 1742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis try: 1762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if filename.endswith('.html') or filename.endswith('.htm'): 1772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.CheckLines(filename, htmlutil.GetScriptLines(f), True) 1782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 1792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.CheckLines(filename, f, False) 1802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis finally: 1812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis f.close() 1822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def CheckLines(self, filename, lines_iter, is_html): 1842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Checks a file, given as an iterable of lines, for warnings and errors. 1852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 1872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis filename: The name of the file to check. 1882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis lines_iter: An iterator that yields one line of the file at a time. 1892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_html: Whether the file being checked is an HTML file with extracted 1902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis contents. 1912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 1932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis A boolean indicating whether the full file could be checked or if checking 1942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis failed prematurely. 1952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 1962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis limited_doc_checks = False 1972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self._limited_doc_files: 1982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for limited_doc_filename in self._limited_doc_files: 1992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if filename.endswith(limited_doc_filename): 2002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis limited_doc_checks = True 2012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis break 2022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis lint_rules = self._lint_rules 2042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis lint_rules.Initialize(self, limited_doc_checks, is_html) 2052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token = self._tokenizer.TokenizeFile(lines_iter) 2072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis parse_error = None 2092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self._metadata_pass: 2102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis try: 2112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._metadata_pass.Reset() 2122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._metadata_pass.Process(token) 2132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis except ecmametadatapass.ParseError, caught_parse_error: 2142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if FLAGS.error_trace: 2152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis traceback.print_exc() 2162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis parse_error = caught_parse_error 2172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis except Exception: 2182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis print 'Internal error in %s' % filename 2192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis traceback.print_exc() 2202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return False 2212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._error_handler.HandleFile(filename, token) 2232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._CheckTokens(token, parse_error=parse_error, 2252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis debug_tokens=FLAGS.debug_tokens) 2262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _CheckTokens(self, token, parse_error, debug_tokens): 2282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Checks a token stream for lint warnings/errors. 2292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 2312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token: The first token in the token stream to check. 2322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis parse_error: A ParseError if any errors occurred. 2332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis debug_tokens: Whether every token should be printed as it is encountered 2342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis during the pass. 2352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 2372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis A boolean indicating whether the full token stream could be checked or if 2382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis checking failed prematurely. 2392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis result = self._ExecutePass(token, self._LintPass, parse_error, debug_tokens) 2412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not result: 2432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return False 2442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._lint_rules.Finalize(self._state_tracker, self._tokenizer.mode) 2462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._error_handler.FinishFile() 2472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return True 2482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _LintPass(self, token): 2502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Checks an individual token for lint warnings/errors. 2512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Used to encapsulate the logic needed to check an individual token so that it 2532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis can be passed to _ExecutePass. 2542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 2562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token: The token to check. 2572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._lint_rules.CheckToken(token, self._state_tracker) 2592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _ExecutePass(self, token, pass_function, parse_error=None, 2612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis debug_tokens=False): 2622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Calls the given function for every token in the given token stream. 2632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis As each token is passed to the given function, state is kept up to date and, 2652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis depending on the error_trace flag, errors are either caught and reported, or 2662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis allowed to bubble up so developers can see the full stack trace. If a parse 2672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis error is specified, the pass will proceed as normal until the token causing 2682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis the parse error is reached. 2692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 2712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token: The first token in the token stream. 2722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis pass_function: The function to call for each token in the token stream. 2732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis parse_error: A ParseError if any errors occurred. 2742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis debug_tokens: Whether every token should be printed as it is encountered 2752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis during the pass. 2762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 2782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis A boolean indicating whether the full token stream could be checked or if 2792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis checking failed prematurely. 2802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Raises: 2822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Exception: If any error occurred while calling the given function. 2832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._state_tracker.Reset() 2852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis while token: 2862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if debug_tokens: 2872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis print token 2882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if parse_error and parse_error.token == token: 2902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis message = ('Error parsing file at token "%s". Unable to ' 2912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'check the rest of file.' % token.string) 2922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.HandleError(errors.FILE_DOES_NOT_PARSE, message, token) 2932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._error_handler.FinishFile() 2942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return 2952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis try: 2972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._state_tracker.HandleToken( 2982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token, self._state_tracker.GetLastNonSpaceToken()) 2992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis pass_function(token) 3002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._state_tracker.HandleAfterToken(token) 3012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis except: 3022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if FLAGS.error_trace: 3032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis raise 3042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 3052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.HandleError(errors.FILE_DOES_NOT_PARSE, 3062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis ('Error parsing file at token "%s". Unable to ' 3072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'check the rest of file.' % token.string), 3082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token) 3092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._error_handler.FinishFile() 3102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return False 3112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token = token.next 3122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return True 313