[javascriptlint-commit] SF.net SVN: javascriptlint: [178] trunk
Status: Beta
Brought to you by:
matthiasmiller
|
From: <mat...@us...> - 2008-03-31 13:45:22
|
Revision: 178
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=178&view=rev
Author: matthiasmiller
Date: 2008-03-31 06:45:14 -0700 (Mon, 31 Mar 2008)
Log Message:
-----------
Use spaces instead of tabs.
Modified Paths:
--------------
trunk/DEVELOPMENT
trunk/jsl.py
trunk/pyjsl/conf.py
trunk/pyjsl/jsparse.py
trunk/pyjsl/lint.py
trunk/pyjsl/util.py
trunk/pyjsl/visitation.py
trunk/pyjsl/warnings.py
trunk/pyspidermonkey/pyspidermonkey.c
trunk/setup.py
trunk/test.py
Modified: trunk/DEVELOPMENT
===================================================================
--- trunk/DEVELOPMENT 2008-03-20 21:38:49 UTC (rev 177)
+++ trunk/DEVELOPMENT 2008-03-31 13:45:14 UTC (rev 178)
@@ -1,9 +1,7 @@
** STYLE GUIDELINES
-> Use tabs instead of spaces (for now)
> All lines should be 79 characters or less
-> For everything else, follow http://www.python.org/dev/peps/pep-0008/ as much
- as possible.
+> Follow http://www.python.org/dev/peps/pep-0008/ as much as possible.
** TODO
@@ -23,9 +21,9 @@
SpiderMonkey. Use a relative path for pretty commit messages.
svn_load_dirs.pl \
- -t X.X.X \
- -p svn_load_dirs.conf \
- https://javascriptlint.svn.sourceforge.net/svnroot/javascriptlint/vendorsrc/Mozilla.org/js \
- current \
- js-X.X.X
+ -t X.X.X \
+ -p svn_load_dirs.conf \
+ https://javascriptlint.svn.sourceforge.net/svnroot/javascriptlint/vendorsrc/Mozilla.org/js \
+ current \
+ js-X.X.X
Modified: trunk/jsl.py
===================================================================
--- trunk/jsl.py 2008-03-20 21:38:49 UTC (rev 177)
+++ trunk/jsl.py 2008-03-31 13:45:14 UTC (rev 178)
@@ -7,11 +7,11 @@
import unittest
try:
- import setup
+ import setup
except ImportError:
- pass
+ pass
else:
- sys.path.append(setup.get_lib_path())
+ sys.path.append(setup.get_lib_path())
import pyjsl.conf
import pyjsl.jsparse
@@ -19,84 +19,84 @@
import test
_lint_results = {
- 'warnings': 0,
- 'errors': 0
+ 'warnings': 0,
+ 'errors': 0
}
def get_test_files():
- # Get a list of test files.
- dir_ = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tests')
+ # Get a list of test files.
+ dir_ = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tests')
- all_files = []
- for root, dirs, files in os.walk(dir_):
- all_files += [os.path.join(dir_, root, file) for file in files]
- if '.svn' in dirs:
- dirs.remove('.svn')
- # TODO
- if 'conf' in dirs:
- dirs.remove('conf')
- all_files.sort()
- return all_files
+ all_files = []
+ for root, dirs, files in os.walk(dir_):
+ all_files += [os.path.join(dir_, root, file) for file in files]
+ if '.svn' in dirs:
+ dirs.remove('.svn')
+ # TODO
+ if 'conf' in dirs:
+ dirs.remove('conf')
+ all_files.sort()
+ return all_files
def run_tests():
- for file in get_test_files():
- if file.endswith('.htm') or file.endswith('.html'):
- continue #TODO
- elif file.endswith('.js'):
- try:
- test.run(file)
- except test.TestError, error:
- print error
+ for file in get_test_files():
+ if file.endswith('.htm') or file.endswith('.html'):
+ continue #TODO
+ elif file.endswith('.js'):
+ try:
+ test.run(file)
+ except test.TestError, error:
+ print error
def _dump(paths):
- for path in paths:
- script = pyjsl.util.readfile(path)
- pyjsl.jsparse.dump_tree(script)
+ for path in paths:
+ script = pyjsl.util.readfile(path)
+ pyjsl.jsparse.dump_tree(script)
def _lint(paths, conf):
- def lint_error(path, line, col, errname):
- _lint_results['warnings'] = _lint_results['warnings'] + 1
- print '%s(%i): %s' % (path, line, errname)
- pyjsl.lint.lint_files(paths, lint_error, conf=conf)
+ def lint_error(path, line, col, errname):
+ _lint_results['warnings'] = _lint_results['warnings'] + 1
+ print '%s(%i): %s' % (path, line, errname)
+ pyjsl.lint.lint_files(paths, lint_error, conf=conf)
def _resolve_paths(path, recurse):
- if os.path.isfile(path):
- return [path]
- elif os.path.isdir(path):
- dir = path
- pattern = '*'
- else:
- dir, pattern = os.path.split(path)
+ if os.path.isfile(path):
+ return [path]
+ elif os.path.isdir(path):
+ dir = path
+ pattern = '*'
+ else:
+ dir, pattern = os.path.split(path)
- # Build a list of directories
- dirs = [dir]
- if recurse:
- for cur_root, cur_dirs, cur_files in os.walk(dir):
- for name in cur_dirs:
- dirs.append(os.path.join(cur_root, name))
+ # Build a list of directories
+ dirs = [dir]
+ if recurse:
+ for cur_root, cur_dirs, cur_files in os.walk(dir):
+ for name in cur_dirs:
+ dirs.append(os.path.join(cur_root, name))
- # Glob all files.
- paths = []
- for dir in dirs:
- paths.extend(glob.glob(os.path.join(dir, pattern)))
- return paths
+ # Glob all files.
+ paths = []
+ for dir in dirs:
+ paths.extend(glob.glob(os.path.join(dir, pattern)))
+ return paths
def profile_enabled(func, *args, **kwargs):
- import tempfile
- import hotshot
- import hotshot.stats
- handle, filename = tempfile.mkstemp()
- profile = hotshot.Profile(filename)
- profile.runcall(func, *args, **kwargs)
- profile.close()
- stats = hotshot.stats.load(filename)
- stats = stats.sort_stats("time")
- stats.print_stats()
+ import tempfile
+ import hotshot
+ import hotshot.stats
+ handle, filename = tempfile.mkstemp()
+ profile = hotshot.Profile(filename)
+ profile.runcall(func, *args, **kwargs)
+ profile.close()
+ stats = hotshot.stats.load(filename)
+ stats = stats.sort_stats("time")
+ stats.print_stats()
def profile_disabled(func, *args, **kwargs):
- func(*args, **kwargs)
+ func(*args, **kwargs)
def usage():
- print """
+ print """
Usage:
jsl [files]
--help (-h) print this help
@@ -105,42 +105,42 @@
"""
if __name__ == '__main__':
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'ht:v', ['conf=', 'help', 'test', 'dump', 'unittest', 'profile'])
- except getopt.GetoptError:
- usage()
- sys.exit(2)
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'ht:v', ['conf=', 'help', 'test', 'dump', 'unittest', 'profile'])
+ except getopt.GetoptError:
+ usage()
+ sys.exit(2)
- dump = False
- conf = pyjsl.conf.Conf()
- profile_func = profile_disabled
- for opt, val in opts:
- if opt in ('-h', '--help'):
- usage()
- sys.exit()
- if opt in ('--dump',):
- dump = True
- if opt in ('-t', '--test'):
- profile_func(run_tests)
- if opt in ('--unittest',):
- unittest.main(pyjsl.jsparse, argv=sys.argv[:1])
- if opt in ('--profile',):
- profile_func = profile_enabled
- if opt in ('--conf',):
- conf.loadfile(val)
+ dump = False
+ conf = pyjsl.conf.Conf()
+ profile_func = profile_disabled
+ for opt, val in opts:
+ if opt in ('-h', '--help'):
+ usage()
+ sys.exit()
+ if opt in ('--dump',):
+ dump = True
+ if opt in ('-t', '--test'):
+ profile_func(run_tests)
+ if opt in ('--unittest',):
+ unittest.main(pyjsl.jsparse, argv=sys.argv[:1])
+ if opt in ('--profile',):
+ profile_func = profile_enabled
+ if opt in ('--conf',):
+ conf.loadfile(val)
- paths = []
- for recurse, path in conf['paths']:
- paths.extend(_resolve_paths(path, recurse))
- for arg in args:
- paths.extend(_resolve_paths(arg, False))
- if dump:
- profile_func(_dump, paths)
- else:
- profile_func(_lint, paths, conf)
+ paths = []
+ for recurse, path in conf['paths']:
+ paths.extend(_resolve_paths(path, recurse))
+ for arg in args:
+ paths.extend(_resolve_paths(arg, False))
+ if dump:
+ profile_func(_dump, paths)
+ else:
+ profile_func(_lint, paths, conf)
- if _lint_results['errors']:
- sys.exit(3)
- if _lint_results['warnings']:
- sys.exit(1)
+ if _lint_results['errors']:
+ sys.exit(3)
+ if _lint_results['warnings']:
+ sys.exit(1)
Modified: trunk/pyjsl/conf.py
===================================================================
--- trunk/pyjsl/conf.py 2008-03-20 21:38:49 UTC (rev 177)
+++ trunk/pyjsl/conf.py 2008-03-31 13:45:14 UTC (rev 178)
@@ -3,133 +3,133 @@
import warnings
class ConfError(Exception):
- def __init__(self, error):
- Exception.__init__(error)
- self.lineno = None
- self.path = None
+ def __init__(self, error):
+ Exception.__init__(error)
+ self.lineno = None
+ self.path = None
class Setting:
- wants_parm = False
- wants_dir = False
+ wants_parm = False
+ wants_dir = False
class BooleanSetting(Setting):
- wants_parm = False
- def __init__(self, default):
- self.value = default
- def load(self, enabled):
- self.value = enabled
+ wants_parm = False
+ def __init__(self, default):
+ self.value = default
+ def load(self, enabled):
+ self.value = enabled
class StringSetting(Setting):
- wants_parm = True
- def __init__(self, default):
- self.value = default
- def load(self, enabled, parm):
- if not enabled:
- raise ConfError, 'Expected +.'
- self.value = parm
+ wants_parm = True
+ def __init__(self, default):
+ self.value = default
+ def load(self, enabled, parm):
+ if not enabled:
+ raise ConfError, 'Expected +.'
+ self.value = parm
class DeclareSetting(Setting):
- wants_parm = True
- def __init__(self):
- self.value = []
- def load(self, enabled, parm):
- if not enabled:
- raise ConfError, 'Expected +.'
- self.value.append(parm)
+ wants_parm = True
+ def __init__(self):
+ self.value = []
+ def load(self, enabled, parm):
+ if not enabled:
+ raise ConfError, 'Expected +.'
+ self.value.append(parm)
class ProcessSetting(Setting):
- wants_parm = True
- wants_dir = True
- def __init__(self, recurse_setting):
- self.value = []
- self._recurse = recurse_setting
- def load(self, enabled, parm, dir):
- if dir:
- parm = os.path.join(dir, parm)
- self.value.append((self._recurse.value, parm))
+ wants_parm = True
+ wants_dir = True
+ def __init__(self, recurse_setting):
+ self.value = []
+ self._recurse = recurse_setting
+ def load(self, enabled, parm, dir):
+ if dir:
+ parm = os.path.join(dir, parm)
+ self.value.append((self._recurse.value, parm))
class Conf:
- def __init__(self):
- recurse = BooleanSetting(False)
- self._settings = {
- 'recurse': recurse,
- 'show_context': BooleanSetting(False),
- 'output-format': StringSetting('TODO'),
- 'lambda_assign_requires_semicolon': BooleanSetting(False),
- 'legacy_control_comments': BooleanSetting(True),
- 'jscript_function_extensions': BooleanSetting(False),
- 'always_use_option_explicit': BooleanSetting(False),
- 'define': DeclareSetting(),
- 'context': BooleanSetting(False),
- 'process': ProcessSetting(recurse),
- # SpiderMonkey warnings
- 'no_return_value': BooleanSetting(True),
- 'equal_as_assign': BooleanSetting(True),
- 'anon_no_return_value': BooleanSetting(True)
- }
- for klass in warnings.klasses:
- self._settings[klass.__name__] = BooleanSetting(True)
- self.loadline('-block_without_braces')
+ def __init__(self):
+ recurse = BooleanSetting(False)
+ self._settings = {
+ 'recurse': recurse,
+ 'show_context': BooleanSetting(False),
+ 'output-format': StringSetting('TODO'),
+ 'lambda_assign_requires_semicolon': BooleanSetting(False),
+ 'legacy_control_comments': BooleanSetting(True),
+ 'jscript_function_extensions': BooleanSetting(False),
+ 'always_use_option_explicit': BooleanSetting(False),
+ 'define': DeclareSetting(),
+ 'context': BooleanSetting(False),
+ 'process': ProcessSetting(recurse),
+ # SpiderMonkey warnings
+ 'no_return_value': BooleanSetting(True),
+ 'equal_as_assign': BooleanSetting(True),
+ 'anon_no_return_value': BooleanSetting(True)
+ }
+ for klass in warnings.klasses:
+ self._settings[klass.__name__] = BooleanSetting(True)
+ self.loadline('-block_without_braces')
- def loadfile(self, path):
- path = os.path.abspath(path)
- conf = open(path, 'r').read()
- try:
- self.loadtext(conf, dir=os.path.dirname(path))
- except ConfError, error:
- error.path = path
- raise
+ def loadfile(self, path):
+ path = os.path.abspath(path)
+ conf = open(path, 'r').read()
+ try:
+ self.loadtext(conf, dir=os.path.dirname(path))
+ except ConfError, error:
+ error.path = path
+ raise
- def loadtext(self, conf, dir=None):
- lines = conf.splitlines()
- for lineno in range(0, len(lines)):
- try:
- self.loadline(lines[lineno], dir)
- except ConfError, error:
- error.lineno = lineno
- raise
+ def loadtext(self, conf, dir=None):
+ lines = conf.splitlines()
+ for lineno in range(0, len(lines)):
+ try:
+ self.loadline(lines[lineno], dir)
+ except ConfError, error:
+ error.lineno = lineno
+ raise
- def loadline(self, line, dir=None):
- assert not '\r' in line
- assert not '\n' in line
+ def loadline(self, line, dir=None):
+ assert not '\r' in line
+ assert not '\n' in line
- # Allow comments
- if '#' in line:
- line = line[:line.find('#')]
- line = line.rstrip()
- if not line:
- return
+ # Allow comments
+ if '#' in line:
+ line = line[:line.find('#')]
+ line = line.rstrip()
+ if not line:
+ return
- # Parse the +/-
- if line.startswith('+'):
- enabled = True
- elif line.startswith('-'):
- enabled = False
- else:
- raise ConfError, 'Expected + or -.'
- line = line[1:]
+ # Parse the +/-
+ if line.startswith('+'):
+ enabled = True
+ elif line.startswith('-'):
+ enabled = False
+ else:
+ raise ConfError, 'Expected + or -.'
+ line = line[1:]
- # Parse the key/parms
- name = line.split()[0].lower()
- parm = line[len(name):].lstrip()
+ # Parse the key/parms
+ name = line.split()[0].lower()
+ parm = line[len(name):].lstrip()
- # Load the setting
- setting = self._settings[name]
- args = {
- 'enabled': enabled
- }
- if setting.wants_parm:
- args['parm'] = parm
- elif parm:
- raise ConfError, 'The %s setting does not expect a parameter.' % name
- if setting.wants_dir:
- args['dir'] = dir
- setting.load(**args)
+ # Load the setting
+ setting = self._settings[name]
+ args = {
+ 'enabled': enabled
+ }
+ if setting.wants_parm:
+ args['parm'] = parm
+ elif parm:
+ raise ConfError, 'The %s setting does not expect a parameter.' % name
+ if setting.wants_dir:
+ args['dir'] = dir
+ setting.load(**args)
- def __getitem__(self, name):
- if name == 'paths':
- name = 'process'
- elif name == 'declarations':
- name = 'define'
- return self._settings[name].value
+ def __getitem__(self, name):
+ if name == 'paths':
+ name = 'process'
+ elif name == 'declarations':
+ name = 'define'
+ return self._settings[name].value
Modified: trunk/pyjsl/jsparse.py
===================================================================
--- trunk/pyjsl/jsparse.py 2008-03-20 21:38:49 UTC (rev 177)
+++ trunk/pyjsl/jsparse.py 2008-03-31 13:45:14 UTC (rev 178)
@@ -8,325 +8,325 @@
from pyspidermonkey import tok, op
_tok_names = dict(zip(
- [getattr(tok, prop) for prop in dir(tok)],
- ['tok.%s' % prop for prop in dir(tok)]
+ [getattr(tok, prop) for prop in dir(tok)],
+ ['tok.%s' % prop for prop in dir(tok)]
))
class NodePos:
- def __init__(self, line, col):
- self.line = line
- self.col = col
- def __cmp__(self, other):
- if self.line < other.line:
- return -1
- if self.line > other.line:
- return 1
- if self.col < other.col:
- return -1
- if self.col > other.col:
- return 1
- return 0
- def __str__(self):
- return '(line %i, col %i)' % (self.line+1, self.col+1)
+ def __init__(self, line, col):
+ self.line = line
+ self.col = col
+ def __cmp__(self, other):
+ if self.line < other.line:
+ return -1
+ if self.line > other.line:
+ return 1
+ if self.col < other.col:
+ return -1
+ if self.col > other.col:
+ return 1
+ return 0
+ def __str__(self):
+ return '(line %i, col %i)' % (self.line+1, self.col+1)
class NodePositions:
- " Given a string, allows [x] lookups for NodePos line and column numbers."
- def __init__(self, text):
- # Find the length of each line and incrementally sum all of the lengths
- # to determine the ending position of each line.
- self._lines = text.splitlines(True)
- lines = [0] + [len(x) for x in self._lines]
- for x in range(1, len(lines)):
- lines[x] += lines[x-1]
- self._line_offsets = lines
- def from_offset(self, offset):
- line = bisect.bisect(self._line_offsets, offset)-1
- col = offset - self._line_offsets[line]
- return NodePos(line, col)
- def to_offset(self, pos):
- offset = self._line_offsets[pos.line] + pos.col
- assert offset <= self._line_offsets[pos.line+1] # out-of-bounds col num
- return offset
- def text(self, start, end):
- assert start <= end
- # Trim the ending first in case it's a single line.
- lines = self._lines[start.line:end.line+1]
- lines[-1] = lines[-1][:end.col+1]
- lines[0] = lines[0][start.col:]
- return ''.join(lines)
+ " Given a string, allows [x] lookups for NodePos line and column numbers."
+ def __init__(self, text):
+ # Find the length of each line and incrementally sum all of the lengths
+ # to determine the ending position of each line.
+ self._lines = text.splitlines(True)
+ lines = [0] + [len(x) for x in self._lines]
+ for x in range(1, len(lines)):
+ lines[x] += lines[x-1]
+ self._line_offsets = lines
+ def from_offset(self, offset):
+ line = bisect.bisect(self._line_offsets, offset)-1
+ col = offset - self._line_offsets[line]
+ return NodePos(line, col)
+ def to_offset(self, pos):
+ offset = self._line_offsets[pos.line] + pos.col
+ assert offset <= self._line_offsets[pos.line+1] # out-of-bounds col num
+ return offset
+ def text(self, start, end):
+ assert start <= end
+ # Trim the ending first in case it's a single line.
+ lines = self._lines[start.line:end.line+1]
+ lines[-1] = lines[-1][:end.col+1]
+ lines[0] = lines[0][start.col:]
+ return ''.join(lines)
class NodeRanges:
- def __init__(self):
- self._offsets = []
- def add(self, start, end):
- i = bisect.bisect_left(self._offsets, start)
- if i % 2 == 1:
- i -= 1
- start = self._offsets[i]
+ def __init__(self):
+ self._offsets = []
+ def add(self, start, end):
+ i = bisect.bisect_left(self._offsets, start)
+ if i % 2 == 1:
+ i -= 1
+ start = self._offsets[i]
- end = end + 1
- j = bisect.bisect_left(self._offsets, end)
- if j % 2 == 1:
- end = self._offsets[j]
- j += 1
+ end = end + 1
+ j = bisect.bisect_left(self._offsets, end)
+ if j % 2 == 1:
+ end = self._offsets[j]
+ j += 1
- self._offsets[i:j] = [start,end]
- def has(self, pos):
- return bisect.bisect_right(self._offsets, pos) % 2 == 1
+ self._offsets[i:j] = [start,end]
+ def has(self, pos):
+ return bisect.bisect_right(self._offsets, pos) % 2 == 1
class _Node:
- def add_child(self, node):
- if node:
- node.node_index = len(self.kids)
- node.parent = self
- self.kids.append(node)
-
- def start_pos(self):
- try:
- return self._start_pos
- except AttributeError:
- self._start_pos = NodePos(self._start_line, self._start_col)
- return self._start_pos
+ def add_child(self, node):
+ if node:
+ node.node_index = len(self.kids)
+ node.parent = self
+ self.kids.append(node)
+
+ def start_pos(self):
+ try:
+ return self._start_pos
+ except AttributeError:
+ self._start_pos = NodePos(self._start_line, self._start_col)
+ return self._start_pos
- def end_pos(self):
- try:
- return self._end_pos
- except AttributeError:
- self._end_pos = NodePos(self._end_line, self._end_col)
- return self._end_pos
+ def end_pos(self):
+ try:
+ return self._end_pos
+ except AttributeError:
+ self._end_pos = NodePos(self._end_line, self._end_col)
+ return self._end_pos
- def __str__(self):
- kind = self.kind
- if not kind:
- kind = '(none)'
- return '%s>%s' % (_tok_names[kind], str(self.kids))
+ def __str__(self):
+ kind = self.kind
+ if not kind:
+ kind = '(none)'
+ return '%s>%s' % (_tok_names[kind], str(self.kids))
- def is_equivalent(self, other, are_functions_equiv=False):
- if not other:
- return False
+ def is_equivalent(self, other, are_functions_equiv=False):
+ if not other:
+ return False
- # Bail out for functions
- if not are_functions_equiv:
- if self.kind == tok.FUNCTION:
- return False
- if self.kind == tok.LP and self.opcode == op.CALL:
- return False
+ # Bail out for functions
+ if not are_functions_equiv:
+ if self.kind == tok.FUNCTION:
+ return False
+ if self.kind == tok.LP and self.opcode == op.CALL:
+ return False
- if self.kind != other.kind:
- return False
- if self.opcode != other.opcode:
- return False
+ if self.kind != other.kind:
+ return False
+ if self.opcode != other.opcode:
+ return False
- # Check atoms on names, properties, and string constants
- if self.kind in (tok.NAME, tok.DOT, tok.STRING) and self.atom != other.atom:
- return False
+ # Check atoms on names, properties, and string constants
+ if self.kind in (tok.NAME, tok.DOT, tok.STRING) and self.atom != other.atom:
+ return False
- # Check values on numbers
- if self.kind == tok.NUMBER and self.dval != other.dval:
- return False
+ # Check values on numbers
+ if self.kind == tok.NUMBER and self.dval != other.dval:
+ return False
- # Compare child nodes
- if len(self.kids) != len(other.kids):
- return False
- for i in range(0, len(self.kids)):
- # Watch for dead nodes
- if not self.kids[i]:
- if not other.kids[i]: return True
- else: return False
- if not self.kids[i].is_equivalent(other.kids[i]):
- return False
+ # Compare child nodes
+ if len(self.kids) != len(other.kids):
+ return False
+ for i in range(0, len(self.kids)):
+ # Watch for dead nodes
+ if not self.kids[i]:
+ if not other.kids[i]: return True
+ else: return False
+ if not self.kids[i].is_equivalent(other.kids[i]):
+ return False
- return True
+ return True
def _parse_comments(script, root, node_positions, ignore_ranges):
- pos = 0
- single_line_re = r"//[^\r\n]*"
- multi_line_re = r"/\*(.*?)\*/"
- full_re = "(%s)|(%s)" % (single_line_re, multi_line_re)
- comment_re = re.compile(full_re, re.DOTALL)
+ pos = 0
+ single_line_re = r"//[^\r\n]*"
+ multi_line_re = r"/\*(.*?)\*/"
+ full_re = "(%s)|(%s)" % (single_line_re, multi_line_re)
+ comment_re = re.compile(full_re, re.DOTALL)
- comments = []
- while True:
- match = comment_re.search(script, pos)
- if not match:
- return comments
+ comments = []
+ while True:
+ match = comment_re.search(script, pos)
+ if not match:
+ return comments
- # Get the comment text
- comment_text = script[match.start():match.end()]
- if comment_text.startswith('/*'):
- comment_text = comment_text[2:-2]
- opcode = 'JSOP_C_COMMENT'
- else:
- comment_text = comment_text[2:]
- opcode = 'JSOP_CPP_COMMENT'
- opcode = opcode[5:].lower()
+ # Get the comment text
+ comment_text = script[match.start():match.end()]
+ if comment_text.startswith('/*'):
+ comment_text = comment_text[2:-2]
+ opcode = 'JSOP_C_COMMENT'
+ else:
+ comment_text = comment_text[2:]
+ opcode = 'JSOP_CPP_COMMENT'
+ opcode = opcode[5:].lower()
- start_offset = match.start()+1
- end_offset = match.end()
+ start_offset = match.start()+1
+ end_offset = match.end()
- # Make sure it doesn't start in a string or regexp
- if not ignore_ranges.has(start_offset):
- start_pos = node_positions.from_offset(start_offset)
- end_pos = node_positions.from_offset(end_offset)
- kwargs = {
- 'type': 'COMMENT',
- 'atom': comment_text,
- 'opcode': opcode,
- '_start_line': start_pos.line,
- '_start_col': start_pos.col,
- '_end_line': end_pos.line,
- '_end_col': end_pos.col,
- 'parent': None,
- 'kids': [],
- 'node_index': None
- }
- comment_node = _Node()
- comment_node.__dict__.update(kwargs)
- comments.append(comment_node)
- pos = match.end()
- else:
- pos = match.start()+1
+ # Make sure it doesn't start in a string or regexp
+ if not ignore_ranges.has(start_offset):
+ start_pos = node_positions.from_offset(start_offset)
+ end_pos = node_positions.from_offset(end_offset)
+ kwargs = {
+ 'type': 'COMMENT',
+ 'atom': comment_text,
+ 'opcode': opcode,
+ '_start_line': start_pos.line,
+ '_start_col': start_pos.col,
+ '_end_line': end_pos.line,
+ '_end_col': end_pos.col,
+ 'parent': None,
+ 'kids': [],
+ 'node_index': None
+ }
+ comment_node = _Node()
+ comment_node.__dict__.update(kwargs)
+ comments.append(comment_node)
+ pos = match.end()
+ else:
+ pos = match.start()+1
def parse(script, error_callback):
- def _wrapped_callback(line, col, msg):
- assert msg.startswith('JSMSG_')
- msg = msg[6:].lower()
- error_callback(line, col, msg)
+ def _wrapped_callback(line, col, msg):
+ assert msg.startswith('JSMSG_')
+ msg = msg[6:].lower()
+ error_callback(line, col, msg)
- positions = NodePositions(script)
+ positions = NodePositions(script)
- roots = []
- nodes = []
- comment_ignore_ranges = NodeRanges()
- def process(node):
- if node.kind == tok.NUMBER:
- node.atom = positions.text(node.start_pos(), node.end_pos())
- elif node.kind == tok.STRING or \
- (node.kind == tok.OBJECT and node.opcode == op.REGEXP):
- start_offset = positions.to_offset(node.start_pos())
- end_offset = positions.to_offset(node.end_pos())
- comment_ignore_ranges.add(start_offset, end_offset)
- for kid in node.kids:
- if kid:
- process(kid)
- def pop():
- nodes.pop()
+ roots = []
+ nodes = []
+ comment_ignore_ranges = NodeRanges()
+ def process(node):
+ if node.kind == tok.NUMBER:
+ node.atom = positions.text(node.start_pos(), node.end_pos())
+ elif node.kind == tok.STRING or \
+ (node.kind == tok.OBJECT and node.opcode == op.REGEXP):
+ start_offset = positions.to_offset(node.start_pos())
+ end_offset = positions.to_offset(node.end_pos())
+ comment_ignore_ranges.add(start_offset, end_offset)
+ for kid in node.kids:
+ if kid:
+ process(kid)
+ def pop():
+ nodes.pop()
- root_node = pyspidermonkey.parse(script, _Node, _wrapped_callback)
- process(root_node)
+ root_node = pyspidermonkey.parse(script, _Node, _wrapped_callback)
+ process(root_node)
- comments = _parse_comments(script, root_node, positions, comment_ignore_ranges)
- return root_node, comments
+ comments = _parse_comments(script, root_node, positions, comment_ignore_ranges)
+ return root_node, comments
def _dump_node(node, depth=0):
- print '. '*depth,
- if node is None:
- print '(none)'
- else:
- print '%s\t%s, %s' % (_tok_names[node.kind], node.start_pos(), node.end_pos())
- for node in node.kids:
- _dump_node(node, depth+1)
+ print '. '*depth,
+ if node is None:
+ print '(none)'
+ else:
+ print '%s\t%s, %s' % (_tok_names[node.kind], node.start_pos(), node.end_pos())
+ for node in node.kids:
+ _dump_node(node, depth+1)
def dump_tree(script):
- def error_callback(line, col, msg):
- print '(%i, %i): %s', (line, col, msg)
- node, comments = parse(script, error_callback)
- _dump_node(node)
+ def error_callback(line, col, msg):
+ print '(%i, %i): %s', (line, col, msg)
+ node, comments = parse(script, error_callback)
+ _dump_node(node)
class TestComments(unittest.TestCase):
- def _test(self, script, expected_comments):
- root, comments = parse(script, lambda line, col, msg: None)
- encountered_comments = [node.atom for node in comments]
- self.assertEquals(encountered_comments, list(expected_comments))
- def testSimpleComments(self):
- self._test('re = /\//g', ())
- self._test('re = /\///g', ())
- self._test('re = /\////g', ('g',))
- def testCComments(self):
- self._test('/*a*//*b*/', ('a', 'b'))
- self._test('/*a\r\na*//*b\r\nb*/', ('a\r\na', 'b\r\nb'))
- self._test('a//*b*/c', ('*b*/c',))
- self._test('a///*b*/c', ('/*b*/c',))
- self._test('a/*//*/;', ('//',))
- self._test('a/*b*/+/*c*/d', ('b', 'c'))
+ def _test(self, script, expected_comments):
+ root, comments = parse(script, lambda line, col, msg: None)
+ encountered_comments = [node.atom for node in comments]
+ self.assertEquals(encountered_comments, list(expected_comments))
+ def testSimpleComments(self):
+ self._test('re = /\//g', ())
+ self._test('re = /\///g', ())
+ self._test('re = /\////g', ('g',))
+ def testCComments(self):
+ self._test('/*a*//*b*/', ('a', 'b'))
+ self._test('/*a\r\na*//*b\r\nb*/', ('a\r\na', 'b\r\nb'))
+ self._test('a//*b*/c', ('*b*/c',))
+ self._test('a///*b*/c', ('/*b*/c',))
+ self._test('a/*//*/;', ('//',))
+ self._test('a/*b*/+/*c*/d', ('b', 'c'))
class TestNodePositions(unittest.TestCase):
- def _test(self, text, expected_lines, expected_cols):
- # Get a NodePos list
- positions = NodePositions(text)
- positions = [positions.from_offset(i) for i in range(0, len(text))]
- encountered_lines = ''.join([str(x.line) for x in positions])
- encountered_cols = ''.join([str(x.col) for x in positions])
- self.assertEquals(encountered_lines, expected_lines.replace(' ', ''))
- self.assertEquals(encountered_cols, expected_cols.replace(' ', ''))
- def testSimple(self):
- self._test(
- 'abc\r\ndef\nghi\n\nj',
- '0000 0 1111 2222 3 4',
- '0123 4 0123 0123 0 0'
- )
- self._test(
- '\rabc',
- '0 111',
- '0 012'
- )
- def testText(self):
- pos = NodePositions('abc\r\ndef\n\nghi')
- self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 0)), 'a')
- self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 2)), 'abc')
- self.assertEquals(pos.text(NodePos(0, 2), NodePos(1, 2)), 'c\r\ndef')
- def testOffset(self):
- pos = NodePositions('abc\r\ndef\n\nghi')
- self.assertEquals(pos.to_offset(NodePos(0, 2)), 2)
- self.assertEquals(pos.to_offset(NodePos(1, 0)), 5)
- self.assertEquals(pos.to_offset(NodePos(3, 1)), 11)
+ def _test(self, text, expected_lines, expected_cols):
+ # Get a NodePos list
+ positions = NodePositions(text)
+ positions = [positions.from_offset(i) for i in range(0, len(text))]
+ encountered_lines = ''.join([str(x.line) for x in positions])
+ encountered_cols = ''.join([str(x.col) for x in positions])
+ self.assertEquals(encountered_lines, expected_lines.replace(' ', ''))
+ self.assertEquals(encountered_cols, expected_cols.replace(' ', ''))
+ def testSimple(self):
+ self._test(
+ 'abc\r\ndef\nghi\n\nj',
+ '0000 0 1111 2222 3 4',
+ '0123 4 0123 0123 0 0'
+ )
+ self._test(
+ '\rabc',
+ '0 111',
+ '0 012'
+ )
+ def testText(self):
+ pos = NodePositions('abc\r\ndef\n\nghi')
+ self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 0)), 'a')
+ self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 2)), 'abc')
+ self.assertEquals(pos.text(NodePos(0, 2), NodePos(1, 2)), 'c\r\ndef')
+ def testOffset(self):
+ pos = NodePositions('abc\r\ndef\n\nghi')
+ self.assertEquals(pos.to_offset(NodePos(0, 2)), 2)
+ self.assertEquals(pos.to_offset(NodePos(1, 0)), 5)
+ self.assertEquals(pos.to_offset(NodePos(3, 1)), 11)
class TestNodeRanges(unittest.TestCase):
- def testAdd(self):
- r = NodeRanges()
- r.add(5, 10)
- self.assertEquals(r._offsets, [5,11])
- r.add(15, 20)
- self.assertEquals(r._offsets, [5,11,15,21])
- r.add(21,22)
- self.assertEquals(r._offsets, [5,11,15,23])
- r.add(4,5)
- self.assertEquals(r._offsets, [4,11,15,23])
- r.add(9,11)
- self.assertEquals(r._offsets, [4,12,15,23])
- r.add(10,20)
- self.assertEquals(r._offsets, [4,23])
- r.add(4,22)
- self.assertEquals(r._offsets, [4,23])
- r.add(30,30)
- self.assertEquals(r._offsets, [4,23,30,31])
- def testHas(self):
- r = NodeRanges()
- r.add(5, 10)
- r.add(15, 15)
- assert not r.has(4)
- assert r.has(5)
- assert r.has(6)
- assert r.has(9)
- assert r.has(10)
- assert not r.has(14)
- assert r.has(15)
- assert not r.has(16)
+ def testAdd(self):
+ r = NodeRanges()
+ r.add(5, 10)
+ self.assertEquals(r._offsets, [5,11])
+ r.add(15, 20)
+ self.assertEquals(r._offsets, [5,11,15,21])
+ r.add(21,22)
+ self.assertEquals(r._offsets, [5,11,15,23])
+ r.add(4,5)
+ self.assertEquals(r._offsets, [4,11,15,23])
+ r.add(9,11)
+ self.assertEquals(r._offsets, [4,12,15,23])
+ r.add(10,20)
+ self.assertEquals(r._offsets, [4,23])
+ r.add(4,22)
+ self.assertEquals(r._offsets, [4,23])
+ r.add(30,30)
+ self.assertEquals(r._offsets, [4,23,30,31])
+ def testHas(self):
+ r = NodeRanges()
+ r.add(5, 10)
+ r.add(15, 15)
+ assert not r.has(4)
+ assert r.has(5)
+ assert r.has(6)
+ assert r.has(9)
+ assert r.has(10)
+ assert not r.has(14)
+ assert r.has(15)
+ assert not r.has(16)
class TestCompilableUnit(unittest.TestCase):
- def test(self):
- tests = (
- ('var s = "', False),
- ('bogon()', True),
- ('int syntax_error;', True),
- ('a /* b', False),
- ('re = /.*', False),
- ('{ // missing curly', False)
- )
- for text, is_compilable_unit in tests:
- self.assertEquals(pyspidermonkey.is_compilable_unit(text),
- is_compilable_unit)
+ def test(self):
+ tests = (
+ ('var s = "', False),
+ ('bogon()', True),
+ ('int syntax_error;', True),
+ ('a /* b', False),
+ ('re = /.*', False),
+ ('{ // missing curly', False)
+ )
+ for text, is_compilable_unit in tests:
+ self.assertEquals(pyspidermonkey.is_compilable_unit(text),
+ is_compilable_unit)
if __name__ == '__main__':
- unittest.main()
+ unittest.main()
Modified: trunk/pyjsl/lint.py
===================================================================
--- trunk/pyjsl/lint.py 2008-03-20 21:38:49 UTC (rev 177)
+++ trunk/pyjsl/lint.py 2008-03-31 13:45:14 UTC (rev 178)
@@ -11,282 +11,282 @@
from pyspidermonkey import tok, op
_newline_kinds = (
- 'eof', 'comma', 'dot', 'semi', 'colon', 'lc', 'rc', 'lp', 'rb', 'assign',
- 'relop', 'hook', 'plus', 'minus', 'star', 'divop', 'eqop', 'shop', 'or',
- 'and', 'bitor', 'bitxor', 'bitand', 'else', 'try'
+ 'eof', 'comma', 'dot', 'semi', 'colon', 'lc', 'rc', 'lp', 'rb', 'assign',
+ 'relop', 'hook', 'plus', 'minus', 'star', 'divop', 'eqop', 'shop', 'or',
+ 'and', 'bitor', 'bitxor', 'bitand', 'else', 'try'
)
_globals = frozenset([
- 'Array', 'Boolean', 'Math', 'Number', 'String', 'RegExp', 'Script', 'Date',
- 'isNaN', 'isFinite', 'parseFloat', 'parseInt',
- 'eval', 'NaN', 'Infinity',
- 'escape', 'unescape', 'uneval',
- 'decodeURI', 'encodeURI', 'decodeURIComponent', 'encodeURIComponent',
- 'Function', 'Object',
- 'Error', 'InternalError', 'EvalError', 'RangeError', 'ReferenceError',
- 'SyntaxError', 'TypeError', 'URIError',
- 'arguments', 'undefined'
+ 'Array', 'Boolean', 'Math', 'Number', 'String', 'RegExp', 'Script', 'Date',
+ 'isNaN', 'isFinite', 'parseFloat', 'parseInt',
+ 'eval', 'NaN', 'Infinity',
+ 'escape', 'unescape', 'uneval',
+ 'decodeURI', 'encodeURI', 'decodeURIComponent', 'encodeURIComponent',
+ 'Function', 'Object',
+ 'Error', 'InternalError', 'EvalError', 'RangeError', 'ReferenceError',
+ 'SyntaxError', 'TypeError', 'URIError',
+ 'arguments', 'undefined'
])
_identifier = re.compile('^[A-Za-z_$][A-Za-z0-9_$]*$')
def _find_function(node):
- while node and node.kind != tok.FUNCTION:
- node = node.parent
- return node
+ while node and node.kind != tok.FUNCTION:
+ node = node.parent
+ return node
def _find_functions(node):
- functions = []
- while node:
- if node.kind == tok.FUNCTION:
- functions.append(node)
- node = node.parent
- return functions
+ functions = []
+ while node:
+ if node.kind == tok.FUNCTION:
+ functions.append(node)
+ node = node.parent
+ return functions
def _parse_control_comment(comment):
- """ Returns None or (keyword, parms) """
- if comment.atom.lower().startswith('jsl:'):
- control_comment = comment.atom[4:]
- elif comment.atom.startswith('@') and comment.atom.endswith('@'):
- control_comment = comment.atom[1:-1]
- else:
- return None
+ """ Returns None or (keyword, parms) """
+ if comment.atom.lower().startswith('jsl:'):
+ control_comment = comment.atom[4:]
+ elif comment.atom.startswith('@') and comment.atom.endswith('@'):
+ control_comment = comment.atom[1:-1]
+ else:
+ return None
- control_comments = {
- 'ignoreall': (False),
- 'ignore': (False),
- 'end': (False),
- 'option explicit': (False),
- 'import': (True),
- 'fallthru': (False),
- 'pass': (False),
- 'declare': (True)
- }
- if control_comment.lower() in control_comments:
- keyword = control_comment.lower()
- else:
- keyword = control_comment.lower().split()[0]
- if not keyword in control_comments:
- return None
+ control_comments = {
+ 'ignoreall': (False),
+ 'ignore': (False),
+ 'end': (False),
+ 'option explicit': (False),
+ 'import': (True),
+ 'fallthru': (False),
+ 'pass': (False),
+ 'declare': (True)
+ }
+ if control_comment.lower() in control_comments:
+ keyword = control_comment.lower()
+ else:
+ keyword = control_comment.lower().split()[0]
+ if not keyword in control_comments:
+ return None
- parms = control_comment[len(keyword):].strip()
- return (comment, keyword, parms)
+ parms = control_comment[len(keyword):].strip()
+ return (comment, keyword, parms)
class Scope:
- def __init__(self, node):
- self._is_with_scope = node.kind == tok.WITH
- self._parent = None
- self._kids = []
- self._identifiers = {}
- self._references = []
- self._node = node
- def add_scope(self, node):
- self._kids.append(Scope(node))
- self._kids[-1]._parent = self
- if self._is_with_scope:
- self._kids[-1]._is_with_scope = True
- return self._kids[-1]
- def add_declaration(self, name, node):
- if not self._is_with_scope:
- self._identifiers[name] = node
- def add_reference(self, name, node):
- if not self._is_with_scope:
- self._references.append((name, node))
- def get_identifier(self, name):
- if name in self._identifiers:
- return self._identifiers[name]
- else:
- return None
- def get_identifiers(self):
- "returns a list of names"
- return self._identifiers.keys()
- def resolve_identifier(self, name):
- if name in self._identifiers:
- return self, self._identifiers[name]
- if self._parent:
- return self._parent.resolve_identifier(name)
- return None
- def get_undeclared_identifiers(self):
- identifiers = []
- for child in self._kids:
- identifiers += child.get_undeclared_identifiers()
- for name, node in self._references:
- if not self.resolve_identifier(name):
- identifiers.append(node)
- return identifiers
- def find_scope(self, node):
- for kid in self._kids:
- scope = kid.find_scope(node)
- if scope:
- return scope
+ def __init__(self, node):
+ self._is_with_scope = node.kind == tok.WITH
+ self._parent = None
+ self._kids = []
+ self._identifiers = {}
+ self._references = []
+ self._node = node
+ def add_scope(self, node):
+ self._kids.append(Scope(node))
+ self._kids[-1]._parent = self
+ if self._is_with_scope:
+ self._kids[-1]._is_with_scope = True
+ return self._kids[-1]
+ def add_declaration(self, name, node):
+ if not self._is_with_scope:
+ self._identifiers[name] = node
+ def add_reference(self, name, node):
+ if not self._is_with_scope:
+ self._references.append((name, node))
+ def get_identifier(self, name):
+ if name in self._identifiers:
+ return self._identifiers[name]
+ else:
+ return None
+ def get_identifiers(self):
+ "returns a list of names"
+ return self._identifiers.keys()
+ def resolve_identifier(self, name):
+ if name in self._identifiers:
+ return self, self._identifiers[name]
+ if self._parent:
+ return self._parent.resolve_identifier(name)
+ return None
+ def get_undeclared_identifiers(self):
+ identifiers = []
+ for child in self._kids:
+ identifiers += child.get_undeclared_identifiers()
+ for name, node in self._references:
+ if not self.resolve_identifier(name):
+ identifiers.append(node)
+ return identifiers
+ def find_scope(self, node):
+ for kid in self._kids:
+ scope = kid.find_scope(node)
+ if scope:
+ return scope
- # Always add it to the outer scope.
- if not self._parent or \
- (node.start_pos() >= self._node.start_pos() and \
- node.end_pos() <= self._node.end_pos()):
- return self
+ # Always add it to the outer scope.
+ if not self._parent or \
+ (node.start_pos() >= self._node.start_pos() and \
+ node.end_pos() <= self._node.end_pos()):
+ return self
- return None
+ return None
def lint_files(paths, lint_error, conf=conf.Conf()):
- def lint_file(path):
- def import_script(import_path):
- import_path = os.path.join(os.path.dirname(path), import_path)
- return lint_file(import_path)
- def _lint_error(*args):
- return lint_error(normpath, *args)
+ def lint_file(path):
+ def import_script(import_path):
+ import_path = os.path.join(os.path.dirname(path), import_path)
+ return lint_file(import_path)
+ def _lint_error(*args):
+ return lint_error(normpath, *args)
- normpath = util.normpath(path)
- if not normpath in lint_cache:
- lint_cache[normpath] = {}
- script = util.readfile(path)
- print normpath
- _lint_script(script, lint_cache[normpath], _lint_error, conf, import_script)
- return lint_cache[normpath]
+ normpath = util.normpath(path)
+ if not normpath in lint_cache:
+ lint_cache[normpath] = {}
+ script = util.readfile(path)
+ print normpath
+ _lint_script(script, lint_cache[normpath], _lint_error, conf, import_script)
+ return lint_cache[normpath]
- lint_cache = {}
- for path in paths:
- lint_file(path)
+ lint_cache = {}
+ for path in paths:
+ lint_file(path)
def _lint_script(script, script_cache, lint_error, conf, import_callback):
- def parse_error(row, col, msg):
- if not msg in ('redeclared_var', 'var_hides_arg'):
- parse_errors.append((jsparse.NodePos(row, col), msg))
+ def parse_error(row, col, msg):
+ if not msg in ('redeclared_var', 'var_hides_arg'):
+ parse_errors.append((jsparse.NodePos(row, col), msg))
- def report(node, errname):
- _report(node.start_pos(), errname, True)
+ def report(node, errname):
+ _report(node.start_pos(), errname, True)
- def _report(pos, errname, require_key):
- try:
- if not conf[errname]:
- return
- except KeyError, err:
- if require_key:
- raise
+ def _report(pos, errname, require_key):
+ try:
+ if not conf[errname]:
+ return
+ except KeyError, err:
+ if require_key:
+ raise
- for start, end in ignores:
- if pos >= start and pos <= end:
- return
+ for start, end in ignores:
+ if pos >= start and pos <= end:
+ return
- return lint_error(pos.line, pos.col, errname)
+ return lint_error(pos.line, pos.col, errname)
- parse_errors = []
- root, comments = jsparse.parse(script, parse_error)
- ignores = []
- start_ignore = None
- declares = []
- import_paths = []
- for comment in comments:
- cc = _parse_control_comment(comment)
- if cc:
- node, keyword, parms = cc
- if keyword == 'declare':
- if not _identifier.match(parms):
- report(node, 'jsl_cc_not_understood')
- else:
- declares.append((parms, node))
- elif keyword == 'ignore':
- if start_ignore:
- report(node, 'mismatch_ctrl_comments')
- else:
- start_ignore = node
- elif keyword == 'end':
- if start_ignore:
- ignores.append((start_ignore.start_pos(), node.end_pos()))
- start_ignore = None
- else:
- report(node, 'mismatch_ctrl_comments')
- elif keyword == 'import':
- if not parms:
- report(node, 'jsl_cc_not_understood')
- else:
- import_paths.append(parms)
- else:
- if comment.opcode == 'c_comment':
- if '/*' in comment.atom or comment.atom.endswith('/'):
- report(comment, 'nested_comment')
- if comment.atom.lower().startswith('jsl:'):
- report(comment, 'jsl_cc_not_understood')
- elif comment.atom.startswith('@'):
- report(comment, 'legacy_cc_not_understood')
- if start_ignore:
- report(start_ignore, 'mismatch_ctrl_comments')
+ parse_errors = []
+ root, comments = jsparse.parse(script, parse_error)
+ ignores = []
+ start_ignore = None
+ declares = []
+ import_paths = []
+ for comment in comments:
+ cc = _parse_control_comment(comment)
+ if cc:
+ node, keyword, parms = cc
+ if keyword == 'declare':
+ if not _identifier.match(parms):
+ report(node, 'jsl_cc_not_understood')
+ else:
+ declares.append((parms, node))
+ elif keyword == 'ignore':
+ if start_ignore:
+ report(node, 'mismatch_ctrl_comments')
+ else:
+ start_ignore = node
+ elif keyword == 'end':
+ if start_ignore:
+ ignores.append((start_ignore.start_pos(), node.end_pos()))
+ start_ignore = None
+ else:
+ report(node, 'mismatch_ctrl_comments')
+ elif keyword == 'import':
+ if not parms:
+ report(node, 'jsl_cc_not_understood')
+ else:
+ import_paths.append(parms)
+ else:
+ if comment.opcode == 'c_comment':
+ if '/*' in comment.atom or comment.atom.endswith('/'):
+ report(comment, 'nested_comment')
+ if comment.atom.lower().startswith('jsl:'):
+ report(comment, 'jsl_cc_not_understood')
+ elif comment.atom.startswith('@'):
+ report(comment, 'legacy_cc_not_understood')
+ if start_ignore:
+ report(start_ignore, 'mismatch_ctrl_comments')
- # Wait to report parse errors until loading jsl:ignore directives.
- for pos, msg in parse_errors:
- _report(pos, msg, False)
+ # Wait to report parse errors until loading jsl:ignore directives.
+ for pos, msg in parse_errors:
+ _report(pos, msg, False)
- visitors = visitation.make_visitors(warnings.klasses)
+ visitors = visitation.make_visitors(warnings.klasses)
- assert not script_cache
- imports = script_cache['imports'] = set()
- scope = script_cache['scope'] = Scope(root)
+ assert not script_cache
+ imports = script_cache['imports'] = set()
+ scope = script_cache['scope'] = Scope(root)
- # kickoff!
- _lint_node(root, visitors, report, scope)
+ # kickoff!
+ _lint_node(root, visitors, report, scope)
- # Process imports by copying global declarations into the universal scope.
- imports |= set(conf['declarations'])
- imports |= _globals
- for path in import_paths:
- cache = import_callback(path)
- imports |= cache['imports']
- imports |= set(cache['scope'].get_identifiers())
+ # Process imports by copying global declarations into the universal scope.
+ imports |= set(conf['declarations'])
+ imports |= _globals
+ for path in import_paths:
+ cache = import_callback(path)
+ imports |= cache['imports']
+ imports |= set(cache['scope'].get_identifiers())
- for name, node in declares:
- declare_scope = scope.find_scope(node)
- if declare_scope.get_identifier(name):
- report(node, 'redeclared_var')
- else:
- declare_scope.add_declaration(name, node)
+ for name, node in declares:
+ declare_scope = scope.find_scope(node)
+ if declare_scope.get_identifier(name):
+ report(node, 'redeclared_var')
+ else:
+ declare_scope.add_declaration(name, node)
- for node in scope.get_undeclared_identifiers():
- if not node.atom in imports:
- report(node, 'undeclared_identifier')
+ for node in scope.get_undeclared_identifiers():
+ if not node.atom in imports:
+ report(node, 'undeclared_identifier')
def _lint_node(node, visitors, report, scope):
- def warn_or_declare(name, node):
- other = scope.get_identifier(name)
- if other and other.kind == tok.FUNCTION and name in other.fn_args:
- report(node, 'var_hides_arg')
- elif other:
- report(node, 'redeclared_var')
- else:
- scope.add_declaration(name, node)
+ def warn_or_declare(name, node):
+ other = scope.get_identifier(name)
+ if other and other.kind == tok.FUNCTION and name in other.fn_args:
+ report(node, 'var_hides_arg')
+ elif other:
+ report(node, 'redeclared_var')
+ else:
+ scope.add_declaration(name, node)
- # Let the visitors warn.
- for kind in (node.kind, (node.kind, node.opcode)):
- if kind in visitors:
- for visitor in visitors[kind]:
- warning_node = visitor(node)
- if warning_node:
- report(warning_node, visitor.im_class.__name__)
+ # Let the visitors warn.
+ for kind in (node.kind, (node.kind, node.opcode)):
+ if kind in visitors:
+ for visitor in visitors[kind]:
+ warning_node = visitor(node)
+ if warning_node:
+ report(warning_node, visitor.im_class.__name__)
- if node.kind == tok.NAME:
- if node.node_index == 0 and node.parent.kind == tok.COLON and node.parent.parent.kind == tok.RC:
- pass # left side of object literal
- elif node.parent.kind == tok.CATCH:
- scope.add_declaration(node.atom, node)
- else:
- scope.add_reference(node.atom, node)
+ if node.kind == tok.NAME:
+ if node.node_index == 0 and node.parent.kind == tok.COLON and node.parent.parent.kind == tok.RC:
+ pass # left side of object literal
+ elif node.parent.kind == tok.CATCH:
+ scope.add_declaration(node.atom, node)
+ else:
+ scope.add_reference(node.atom, node)
- # Push function identifiers
- if node.kind == tok.FUNCTION:
- if node.fn_name:
- warn_or_declare(node.fn_name, node)
- scope = scope.add_scope(node)
- for var_name in node.fn_args:
- scope.add_declaration(var_name, node)
- elif node.kind == tok.LEXICALSCOPE:
- scope = scope.add_scope(node)
- elif node.kind == tok.WITH:
- scope = scope.add_scope(node)
+ # Push function identifiers
+ if node.kind == tok.FUNCTION:
+ if node.fn_name:
+ warn_or_declare(node.fn_name, node)
+ scope = scope.add_scope(node)
+ for var_name in node.fn_args:
+ scope.add_declaration(var_name, node)
+ elif node.kind == tok.LEXICALSCOPE:
+ scope = scope.add_scope(node)
+ elif node.kind == tok.WITH:
+ scope = scope.add_scope(node)
- if node.parent and node.parent.kind == tok.VAR:
- warn_or_declare(node.atom, node)
+ if node.parent and node.parent.kind == tok.VAR:
+ warn_or_declare(node.atom, node)
- for child in node.kids:
- if child:
- _lint_node(child, visitors, report, scope)
+ for child in node.kids:
+ if child:
+ _lint_node(child, visitors, report, scope)
Modified: trunk/pyjsl/util.py
===================================================================
--- trunk/pyjsl/util.py 2008-03-20 21:38:49 UTC (rev 177)
+++ trunk/pyjsl/util.py 2008-03-31 13:45:14 UTC (rev 178)
@@ -2,15 +2,15 @@
import os.path
def readfile(path):
- file = codecs.open(path, 'r', 'utf-8')
- contents = file.read()
- if contents[0] == unicode(codecs.BOM_UTF8, 'utf8'):
- contents = contents[1:]
- return contents
+ file = codecs.open(path, 'r', 'utf-8')
+ contents = file.read()
+ if contents[0] == unicode(codecs.BOM_UTF8, 'utf8'):
+ contents = contents[1:]
+ return contents
def normpath(path):
- path = os.path.abspath(path)
- path = os.path.normcase(path)
- path = os.path.normpath(path)
- return path
+ path = os.path.abspath(path)
+ path = os.path.normcase(path)
+ path = os.path.normpath(path)
+ return path
Modified: trunk/pyjsl/visitation.py
===================================================================
--- trunk/pyjsl/visitation.py 2008-03-20 21:38:49 UTC (rev 177)
+++ trunk/pyjsl/visitation.py 2008-03-31 13:45:14 UTC (rev 178)
@@ -3,33 +3,33 @@
"""
def visit(*args):
- """ This decorator is used to indicate which nodes the function should
- examine. The function should accept (self, node) and return the relevant
- node or None. """
- def _decorate(fn):
- fn._visit_nodes = args
- return fn
- return _decorate
+ """ This decorator is used to indicate which nodes the function should
+ examine. The function should accept (self, node) and return the relevant
+ node or None. """
+ def _decorate(fn):
+ fn._visit_nodes = args
+ return fn
+ return _decorate
def make_visitors(klasses):
- """ Searches klasses for all member functions decorated with @visit and
- returns a dictionary that maps from node type to visitor function. """
- visitors = {}
+ """ Searches klasses for all member functions decorated with @visit and
+ returns a dictionary that maps from node type to visitor function. """
+ visitors = {}
- # Intantiate an instance of each class
- for klass in klasses:
- if klass.__name__.lower() != klass.__name__:
- raise ValueError, 'class names must be lowercase'
- if not klass.__doc__:
- raise ValueError, 'missing docstring on class'
+ # Intantiate an instance of each class
+ for klass in klasses:
+ if klass.__name__.lower() != klass.__name__:
+ raise ValueError, 'class names must be lowercase'
+ if not klass.__doc__:
+ raise ValueError, 'missing docstring on class'
- # Look for functions with the "_visit_nodes" property.
- visitor = klass()
- for func in [getattr(visitor, name) for name in dir(visitor)]:
- for node_kind in getattr(func, '_visit_nodes', ()):
- # Map from node_kind to the function
- if not node_kind in visitors:
- visitors[node_kind] = []
- visitors[node_kind].append(func)
- return visitors
+ # Look for functions with the "_visit_nodes" property.
+ visitor = klass()
+ for func in [getattr(visitor, name) for name in dir(visitor)]:
+ for node_kind in getattr(func, '_visit_nodes', ()):
+ # Map from node_kind to the function
+ if not node_kind in visitors:
+ visitors[node_kind] = []
+ visitors[node_kind].append(func)
+ return visitors
Modified: trunk/pyjsl/warnings.py
===================================================================
--- trunk/pyjsl/warnings.py 2008-03-20 21:38:49 UTC (rev 177)
+++ trunk/pyjsl/warnings.py 2008-03-31 13:45:14 UTC (rev 178)
@@ -10,12 +10,12 @@
For example:
- class warning_name:
- 'questionable JavaScript coding style'
- @lookat(tok.NODEKIND, (tok.NODEKIND, op.OPCODE))
- def _lint(self, node):
- if questionable:
- return node
+ class warning_name:
+ 'questionable JavaScript coding style'
+ @lookat(tok.NODEKIND, (tok.NODEKIND, op.OPCODE))
+ def _lint(self, node):
+ if questionable:
+ return node
"""
import re
import sys
@@ -27,468 +27,468 @@
# TODO: document inspect, node:opcode, etc
def _get_branch_in_for(node):
- " Returns None if this is not one of the branches in a 'for' "
- if node.parent and node.parent.kind == tok.RESERVED and \
- node.parent.parent.kind == tok.FOR:
- return node.node_index
- return None
+ " Returns None if this is not one of the branches in a 'for' "
+ if node.parent and node.parent.kind == tok.RESERVED and \
+ node.parent.parent.kind == tok.FOR:
+ return node.node_index
+ return None
def _get_exit_points(node):
- if node.kind == tok.LC:
- # Only if the last child contains it
- exit_points = set([None])
- for kid in node.kids:
- # "None" is only a valid exit point for the last statement.
- if None in exit_points:
- exit_points.remove(None)
- if kid:
- exit_points |= _get_exit_points(kid)
- elif node.kind == tok.IF:
- # Only if both branches have an exit point
- cond_, if_, else_ = node.kids
- exit_points = _get_exit_points(if_)
- if else_:
- exit_points |= _get_exit_points(else_)
- elif node.kind == tok.SWITCH:
- exit_points = set([None])
+ if node.kind == tok.LC:
+ # Only if the last child contains it
+ exit_points = set([None])
+ for kid in node.kids:
+ # "None" is only a valid exit point for the last statement.
+ if None in exit_points:
+ exit_points.remove(None)
+ if kid:
+ exit_points |= _get_exit_points(kid)
+ elif node.kind == tok.IF:
+ # Only if both branches have an exit point
+ cond_, if_, else_ = node.kids
+ exit_points = _get_exit_points(if_)
+ if else_:
+ exit_points |= _get_exit_points(else_)
+ elif node.kind == tok.SWITCH:
+ exit_points = set([None])
- switch_has_default = False
- switch_has_final_fallthru = True
+ switch_has_default = False
+ switch_has_final_fallthru = True
- switch_var, switch_stmts = node.kids
- for node in switch_stmts.kids:
- case_val, case_stmt = node.kids
- case_exit_points = _get_exit_points(case_stmt)
- switch_has_default = switch_has_default or node.kind == tok.DEFAULT
- switch_has_final_fallthru = None in case_exit_points
- exit_points |= case_exit_points
+ switch_var, switch_stmts = node.kids
+ for node in switch_stmts.kids:
+ case_val, case_stmt = node.kids
+ case_exit_points = _get_exit_points(case_stmt)
+ switch_has_default = switch_has_default or node.kind == tok.DEFAULT
+ switch_has_final_fallthru = None in case_exit_points
+ exit_points |= case_exit_points
- # Correct the "None" exit point.
- exi...
[truncated message content] |