javascriptlint-commit Mailing List for JavaScript Lint (Page 2)
Status: Beta
Brought to you by:
matthiasmiller
You can subscribe to this list here.
| 2008 |
Jan
|
Feb
|
Mar
(42) |
Apr
(15) |
May
(2) |
Jun
|
Jul
|
Aug
(33) |
Sep
(3) |
Oct
|
Nov
|
Dec
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2009 |
Jan
|
Feb
|
Mar
(5) |
Apr
|
May
(2) |
Jun
|
Jul
|
Aug
(2) |
Sep
|
Oct
(43) |
Nov
(4) |
Dec
(1) |
| 2010 |
Jan
|
Feb
|
Mar
|
Apr
(6) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
|
| 2011 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
| 2013 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(20) |
Oct
(23) |
Nov
|
Dec
(1) |
| 2014 |
Jan
(1) |
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(4) |
Nov
|
Dec
|
| 2016 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(18) |
| 2018 |
Jan
(7) |
Feb
|
Mar
|
Apr
|
May
|
Jun
(8) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
From: <mat...@us...> - 2016-12-23 23:35:43
|
Revision: 362
http://sourceforge.net/p/javascriptlint/code/362
Author: matthiasmiller
Date: 2016-12-23 23:35:40 +0000 (Fri, 23 Dec 2016)
Log Message:
-----------
Centralize ignores and error reporting.
Modified Paths:
--------------
trunk/javascriptlint/lint.py
Modified: trunk/javascriptlint/lint.py
===================================================================
--- trunk/javascriptlint/lint.py 2016-12-23 23:22:15 UTC (rev 361)
+++ trunk/javascriptlint/lint.py 2016-12-23 23:35:40 UTC (rev 362)
@@ -209,6 +209,14 @@
def __init__(self):
self._imports = set()
self.scope = ScopeObject(None, None, 'scope')
+ self._ignores = []
+ def add_ignore(self, start, end):
+ self._ignores.append((start, end))
+ def should_ignore(self, offset):
+ for start, end in self._ignores:
+ if offset >= start and offset <= end:
+ return True
+ return False
def importscript(self, script):
self._imports.add(script)
def hasglobal(self, name):
@@ -276,7 +284,20 @@
import_path = import_path.replace('\\', os.sep)
import_path = os.path.join(os.path.dirname(path), import_path)
return lint_file(import_path, 'js', jsversion, encoding)
- def _lint_error(offset, errname, errdesc):
+
+ def report_lint(node, errname, offset=0, **errargs):
+ assert errname in lintwarnings.warnings, errname
+ if conf[errname]:
+ _report(offset or node.start_offset, errname, errargs)
+
+ def report_parse_error(offset, errname, errargs):
+ assert errname in lintwarnings.errors, errname
+ _report(offset, errname, errargs)
+
+ def _report(offset, errname, errargs):
+ errdesc = lintwarnings.format_error(errname, **errargs)
+ if lint_cache[normpath].should_ignore(offset):
+ return
pos = node_positions.from_offset(offset)
return lint_error(normpath, pos.line, pos.col, errname, errdesc)
@@ -316,7 +337,8 @@
else:
assert False, 'Unsupported file kind: %s' % kind
- _lint_script_parts(script_parts, lint_cache[normpath], _lint_error, conf, import_script)
+ _lint_script_parts(script_parts, lint_cache[normpath], report_lint, report_parse_error,
+ conf, import_script)
return lint_cache[normpath]
lint_cache = {}
@@ -328,7 +350,7 @@
lint_file(path, 'js', None, encoding)
def _lint_script_part(script_offset, jsversion, script, script_cache, conf,
- ignores, report_parse_error, report_lint, import_callback):
+ report_parse_error, report_lint, import_callback):
def parse_error(offset, msg, msg_args):
if not msg in ('anon_no_return_value', 'no_return_value',
'redeclared_var', 'var_hides_arg'):
@@ -432,7 +454,7 @@
start_ignore = node
elif keyword == 'end':
if start_ignore:
- ignores.append((start_ignore.start_offset, node.end_offset))
+ script_cache.add_ignore(start_ignore.start_offset, node.end_offset)
start_ignore = None
else:
report(node, 'mismatch_ctrl_comments')
@@ -501,28 +523,11 @@
for node in jsparse.find_trailing_whitespace(script, script_offset):
report(node, 'trailing_whitespace')
-def _lint_script_parts(script_parts, script_cache, lint_error, conf, import_callback):
- def report_lint(node, errname, offset=0, **errargs):
- assert errname in lintwarnings.warnings, errname
- if conf[errname]:
- _report(offset or node.start_offset, errname, errargs)
+def _lint_script_parts(script_parts, script_cache, report_lint, report_parse_error, conf,
+ import_callback):
- def report_parse_error(offset, errname, errargs):
- assert errname in lintwarnings.errors, errname
- _report(offset, errname, errargs)
-
- def _report(offset, errname, errargs):
- errdesc = lintwarnings.format_error(errname, **errargs)
-
- for start, end in ignores:
- if offset >= start and offset <= end:
- return
-
- return lint_error(offset, errname, errdesc)
-
for script_offset, jsversion, script in script_parts:
- ignores = []
- _lint_script_part(script_offset, jsversion, script, script_cache, conf, ignores,
+ _lint_script_part(script_offset, jsversion, script, script_cache, conf,
report_parse_error, report_lint, import_callback)
scope = script_cache.scope
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2016-12-23 23:22:17
|
Revision: 361
http://sourceforge.net/p/javascriptlint/code/361
Author: matthiasmiller
Date: 2016-12-23 23:22:15 +0000 (Fri, 23 Dec 2016)
Log Message:
-----------
Clarify report_native vs. report_lint.
Modified Paths:
--------------
trunk/javascriptlint/lint.py
Modified: trunk/javascriptlint/lint.py
===================================================================
--- trunk/javascriptlint/lint.py 2016-12-23 22:31:12 UTC (rev 360)
+++ trunk/javascriptlint/lint.py 2016-12-23 23:22:15 UTC (rev 361)
@@ -328,7 +328,7 @@
lint_file(path, 'js', None, encoding)
def _lint_script_part(script_offset, jsversion, script, script_cache, conf,
- ignores, report_native, report_lint, import_callback):
+ ignores, report_parse_error, report_lint, import_callback):
def parse_error(offset, msg, msg_args):
if not msg in ('anon_no_return_value', 'no_return_value',
'redeclared_var', 'var_hides_arg'):
@@ -401,7 +401,7 @@
if not root:
# Report errors and quit.
for offset, msg, msg_args in parse_errors:
- report_native(offset, msg, msg_args)
+ report_parse_error(offset, msg, msg_args)
return
comments = jsparse.filtercomments(possible_comments, root)
@@ -465,7 +465,7 @@
# Wait to report parse errors until loading jsl:ignore directives.
for offset, msg in parse_errors:
- report_native(offset, msg)
+ report_parse_error(offset, msg)
# Find all visitors and convert them into "onpush" callbacks that call "report"
visitors = {
@@ -503,21 +503,17 @@
def _lint_script_parts(script_parts, script_cache, lint_error, conf, import_callback):
def report_lint(node, errname, offset=0, **errargs):
- errdesc = lintwarnings.format_error(errname, **errargs)
- _report(offset or node.start_offset, errname, errdesc, True)
+ assert errname in lintwarnings.warnings, errname
+ if conf[errname]:
+ _report(offset or node.start_offset, errname, errargs)
- def report_native(offset, errname, errargs):
+ def report_parse_error(offset, errname, errargs):
+ assert errname in lintwarnings.errors, errname
+ _report(offset, errname, errargs)
+
+ def _report(offset, errname, errargs):
errdesc = lintwarnings.format_error(errname, **errargs)
- _report(offset, errname, errdesc, False)
- def _report(offset, errname, errdesc, require_key):
- try:
- if not conf[errname]:
- return
- except KeyError, err:
- if require_key:
- raise
-
for start, end in ignores:
if offset >= start and offset <= end:
return
@@ -527,7 +523,7 @@
for script_offset, jsversion, script in script_parts:
ignores = []
_lint_script_part(script_offset, jsversion, script, script_cache, conf, ignores,
- report_native, report_lint, import_callback)
+ report_parse_error, report_lint, import_callback)
scope = script_cache.scope
identifier_warnings = scope.get_identifier_warnings()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2016-12-23 22:31:14
|
Revision: 360
http://sourceforge.net/p/javascriptlint/code/360
Author: matthiasmiller
Date: 2016-12-23 22:31:12 +0000 (Fri, 23 Dec 2016)
Log Message:
-----------
Clean up imports.
Modified Paths:
--------------
trunk/javascriptlint/jsl.py
trunk/javascriptlint/jsparse.py
trunk/javascriptlint/lint.py
trunk/javascriptlint/lintwarnings.py
trunk/jsengine/structs.py
Modified: trunk/javascriptlint/jsl.py
===================================================================
--- trunk/javascriptlint/jsl.py 2016-12-23 22:27:20 UTC (rev 359)
+++ trunk/javascriptlint/jsl.py 2016-12-23 22:31:12 UTC (rev 360)
@@ -1,9 +1,7 @@
#!/usr/bin/python
# vim: ts=4 sw=4 expandtab
-import codecs
import fnmatch
import functools
-import glob
import os
import sys
import unittest
Modified: trunk/javascriptlint/jsparse.py
===================================================================
--- trunk/javascriptlint/jsparse.py 2016-12-23 22:27:20 UTC (rev 359)
+++ trunk/javascriptlint/jsparse.py 2016-12-23 22:31:12 UTC (rev 360)
@@ -42,7 +42,7 @@
start_offset = match.start()
end_offset = match.end()-1
- comment_node = ParseNode(kind.COMMENT, opcode,
+ comment_node = ParseNode(tok.COMMENT, opcode,
script_offset + start_offset,
script_offset + end_offset, comment_text, [])
comments.append(comment_node)
@@ -95,7 +95,7 @@
for match in trailing_whitespace.finditer(script):
start = match.start('whitespace')
end = match.end('whitespace')
- nodes.append(ParseNode(kind.WHITESPACE, None,
+ nodes.append(ParseNode(tok.WHITESPACE, None,
script_offset + start,
script_offset + end-1,
script[start:end], []))
Modified: trunk/javascriptlint/lint.py
===================================================================
--- trunk/javascriptlint/lint.py 2016-12-23 22:27:20 UTC (rev 359)
+++ trunk/javascriptlint/lint.py 2016-12-23 22:31:12 UTC (rev 360)
@@ -1,7 +1,6 @@
#!/usr/bin/python
# vim: ts=4 sw=4 expandtab
import os.path
-import re
import conf
import fs
Modified: trunk/javascriptlint/lintwarnings.py
===================================================================
--- trunk/javascriptlint/lintwarnings.py 2016-12-23 22:27:20 UTC (rev 359)
+++ trunk/javascriptlint/lintwarnings.py 2016-12-23 22:31:12 UTC (rev 360)
@@ -16,8 +16,6 @@
"""
import itertools
import re
-import sys
-import types
import util
Modified: trunk/jsengine/structs.py
===================================================================
--- trunk/jsengine/structs.py 2016-12-23 22:27:20 UTC (rev 359)
+++ trunk/jsengine/structs.py 2016-12-23 22:31:12 UTC (rev 360)
@@ -5,6 +5,8 @@
from parser._constants_kind import kind
from parser._constants_op import op
+__all__ = ['NodePositions', 'NodePos', 'NodeRanges', 'ParseNode']
+
class NodePositions:
" Given a string, allows [x] lookups for NodePos line and column numbers."
def __init__(self, text, start_pos=None):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2016-12-23 22:27:22
|
Revision: 359
http://sourceforge.net/p/javascriptlint/code/359
Author: matthiasmiller
Date: 2016-12-23 22:27:20 +0000 (Fri, 23 Dec 2016)
Log Message:
-----------
Remove more unused code.
Modified Paths:
--------------
trunk/javascriptlint/lint.py
trunk/javascriptlint/lintwarnings.py
Removed Paths:
-------------
trunk/javascriptlint/visitation.py
Modified: trunk/javascriptlint/lint.py
===================================================================
--- trunk/javascriptlint/lint.py 2016-12-23 21:56:37 UTC (rev 358)
+++ trunk/javascriptlint/lint.py 2016-12-23 22:27:20 UTC (rev 359)
@@ -8,7 +8,6 @@
import htmlparse
import jsparse
import lintwarnings
-import visitation
import unittest
import util
@@ -478,7 +477,7 @@
visitors[event][kind] = [_getreporter(callback, report) for callback in callbacks]
# Push the scope/variable checks.
- visitation.make_visitors(visitors, [_get_scope_checks(script_cache.scope, report)])
+ _get_scope_checks(visitors, script_cache.scope, report)
# kickoff!
_lint_node(root, visitors)
@@ -582,43 +581,44 @@
else:
scope.add_declaration(name, node, type_)
-def _get_scope_checks(scope, report):
+def _get_scope_checks(visitors, scope, report):
scopes = [scope]
- class scope_checks:
- """ This is a non-standard visitation class to track scopes. The
- docstring is unused since this class never throws lint errors.
- """
- @visitation.visit('push', tok.NAME)
- def _name(self, node):
- if node.node_index == 0 and node.parent.kind == tok.COLON and node.parent.parent.kind == tok.RC:
- return # left side of object literal
- if node.parent.kind == tok.VAR:
- _warn_or_declare(scopes[-1], node.atom, 'var', node, report)
- return
- if node.parent.kind == tok.CATCH:
- scopes[-1].add_declaration(node.atom, node, 'var')
- scopes[-1].add_reference(node.atom, node)
+ def _visit(event, *args):
+ def _decorate(fn):
+ for arg in args:
+ visitors.setdefault(event, {}).setdefault(arg, []).append(fn)
+ return fn
+ return _decorate
- @visitation.visit('push', tok.FUNCTION)
- def _push_func(self, node):
- if node.opcode in (None, op.CLOSURE) and node.fn_name:
- _warn_or_declare(scopes[-1], node.fn_name, 'function', node, report)
- self._push_scope(node)
- for var_name in node.fn_args:
- if scopes[-1].has_property(var_name.atom):
- report(var_name, 'duplicate_formal', name=var_name.atom)
- scopes[-1].add_declaration(var_name.atom, var_name, 'arg')
+ @_visit('push', tok.NAME)
+ def _push_name(node):
+ if node.node_index == 0 and node.parent.kind == tok.COLON and node.parent.parent.kind == tok.RC:
+ return # left side of object literal
+ if node.parent.kind == tok.VAR:
+ _warn_or_declare(scopes[-1], node.atom, 'var', node, report)
+ return
+ if node.parent.kind == tok.CATCH:
+ scopes[-1].add_declaration(node.atom, node, 'var')
+ scopes[-1].add_reference(node.atom, node)
- @visitation.visit('push', tok.LEXICALSCOPE, tok.WITH)
- def _push_scope(self, node):
- scopes.append(scopes[-1].add_scope(node))
+ @_visit('push', tok.FUNCTION)
+ def _push_func(node):
+ if node.opcode in (None, op.CLOSURE) and node.fn_name:
+ _warn_or_declare(scopes[-1], node.fn_name, 'function', node, report)
+ _push_scope(node)
+ for var_name in node.fn_args:
+ if scopes[-1].has_property(var_name.atom):
+ report(var_name, 'duplicate_formal', name=var_name.atom)
+ scopes[-1].add_declaration(var_name.atom, var_name, 'arg')
- @visitation.visit('pop', tok.FUNCTION, tok.LEXICALSCOPE, tok.WITH)
- def _pop_scope(self, node):
- scopes.pop()
+ @_visit('push', tok.LEXICALSCOPE, tok.WITH)
+ def _push_scope(node):
+ scopes.append(scopes[-1].add_scope(node))
- return scope_checks
+ @_visit('pop', tok.FUNCTION, tok.LEXICALSCOPE, tok.WITH)
+ def _pop_scope(node):
+ scopes.pop()
def _lint_node(node, visitors):
Modified: trunk/javascriptlint/lintwarnings.py
===================================================================
--- trunk/javascriptlint/lintwarnings.py 2016-12-23 21:56:37 UTC (rev 358)
+++ trunk/javascriptlint/lintwarnings.py 2016-12-23 22:27:20 UTC (rev 359)
@@ -20,7 +20,6 @@
import types
import util
-import visitation
from jsengine.parser import kind as tok
from jsengine.parser import op
Deleted: trunk/javascriptlint/visitation.py
===================================================================
--- trunk/javascriptlint/visitation.py 2016-12-23 21:56:37 UTC (rev 358)
+++ trunk/javascriptlint/visitation.py 2016-12-23 22:27:20 UTC (rev 359)
@@ -1,52 +0,0 @@
-# vim: ts=4 sw=4 expandtab
-""" This is an abstract module for visiting specific nodes. This is useed to
-traverse the tree to generate warnings.
-"""
-
-def visit(event, *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_event = event
- fn._visit_nodes = args
- return fn
- return _decorate
-
-def make_visitors(visitors, klasses):
- """ Searches klasses for all member functions decorated with @visit and
- fills a dictionary that looks like:
- visitors = {
- 'event_name': {
- 'node_type' : [func1, func2]
- }
- }
- """
- assert isinstance(visitors, dict)
-
- # 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 %s' % klass.__name__)
-
- # Look for functions with the "_visit_nodes" property.
- visitor = klass()
- for func in [getattr(visitor, name) for name in dir(visitor)]:
- event_visitors = None
- for node_kind in getattr(func, '_visit_nodes', ()):
- # Group visitors by event (e.g. push vs pop)
- if not event_visitors:
- try:
- event_visitors = visitors[func._visit_event]
- except KeyError:
- event_visitors = visitors[func._visit_event] = {}
-
- # Map from node_kind to the function
- try:
- event_visitors[node_kind].append(func)
- except KeyError:
- event_visitors[node_kind] = [func]
- return visitors
-
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2016-12-23 21:56:39
|
Revision: 358
http://sourceforge.net/p/javascriptlint/code/358
Author: matthiasmiller
Date: 2016-12-23 21:56:37 +0000 (Fri, 23 Dec 2016)
Log Message:
-----------
Remove unused code.
Modified Paths:
--------------
trunk/javascriptlint/lint.py
Modified: trunk/javascriptlint/lint.py
===================================================================
--- trunk/javascriptlint/lint.py 2016-12-23 21:29:43 UTC (rev 357)
+++ trunk/javascriptlint/lint.py 2016-12-23 21:56:37 UTC (rev 358)
@@ -15,12 +15,6 @@
from jsengine.parser import kind as tok
from jsengine.parser import 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'
-)
-
_globals = frozenset([
'Array', 'Boolean', 'Math', 'Number', 'String', 'RegExp', 'Script', 'Date',
'isNaN', 'isFinite', 'parseFloat', 'parseInt',
@@ -33,19 +27,6 @@
'arguments', 'undefined'
])
-def _find_function(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
-
def _parse_control_comment(comment):
""" Returns None or (keyword, parms) """
comment_atom = comment.atom.strip()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2016-12-23 21:29:46
|
Revision: 357
http://sourceforge.net/p/javascriptlint/code/357
Author: matthiasmiller
Date: 2016-12-23 21:29:43 +0000 (Fri, 23 Dec 2016)
Log Message:
-----------
Refactoring the scope object.
Modified Paths:
--------------
trunk/javascriptlint/lint.py
Modified: trunk/javascriptlint/lint.py
===================================================================
--- trunk/javascriptlint/lint.py 2016-12-23 20:47:15 UTC (rev 356)
+++ trunk/javascriptlint/lint.py 2016-12-23 21:29:43 UTC (rev 357)
@@ -76,54 +76,61 @@
parms = control_comment[len(keyword):].strip()
return (comment, keyword, parms.strip())
-class Scope:
+class ScopeObject:
""" Outer-level scopes will never be associated with a node.
Inner-level scopes will always be associated with a node.
"""
- def __init__(self):
- self._parent = None
+ def __init__(self, parent, node, type_):
+ assert type_ in ('scope', 'arg', 'function', 'var'), \
+ 'Unrecognized identifier type: %s' % type_
+ self._parent = parent
+ self._node = node
+ self._type = type_
self._kids = []
self._identifiers = {}
self._references = []
self._unused = []
- self._node = None
+
+ @property
+ def parent_scope(self):
+ return self._parent
+
+ @property
+ def node(self):
+ return self._node
+
def add_scope(self, node):
assert not node is None
- self._kids.append(Scope())
+ self._kids.append(ScopeObject(self, node, 'scope'))
self._kids[-1]._parent = self
self._kids[-1]._node = node
return self._kids[-1]
+
def add_declaration(self, name, node, type_):
- assert type_ in ('arg', 'function', 'var'), \
- 'Unrecognized identifier type: %s' % type_
assert isinstance(name, basestring)
- self._identifiers[name] = {
- 'node': node,
- 'type': type_
- }
+ self._identifiers[name] = ScopeObject(self, node, type_)
+
def add_reference(self, name, node):
self._references.append((name, node))
+
def set_unused(self, name, node):
self._unused.append((name, node))
- def get_identifier(self, name):
+
+ def has_property(self, name):
+ return name in self._identifiers
+
+ def get_property_type(self, name):
if name in self._identifiers:
- return self._identifiers[name]['node']
+ return self._identifiers[name]._type
else:
return None
- def get_identifier_type(self, name):
+ def resolve_property(self, name):
if name in self._identifiers:
- return self._identifiers[name]['type']
- 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]['node']
+ return self._identifiers[name]
if self._parent:
- return self._parent.resolve_identifier(name)
+ return self._parent.resolve_property(name)
return None
+
def get_identifier_warnings(self):
""" Returns a tuple of unreferenced and undeclared, where each is a list
of (scope, name, node) tuples.
@@ -147,6 +154,7 @@
'undeclared': undeclared,
'obstructive': obstructive,
}
+
def _find_warnings(self, unreferenced, undeclared, obstructive,
is_in_with_scope):
""" unreferenced is a dictionary, such that:
@@ -166,25 +174,25 @@
# them if they are referenced. Variables need to be keyed by name
# instead of node, because function parameters share the same node.
for name, info in self._identifiers.items():
- unreferenced[(self, name)] = info['node']
+ unreferenced[(self, name)] = info.node
# Check for variables that hide an identifier in a parent scope.
if self._parent:
for name, info in self._identifiers.items():
- if self._parent.resolve_identifier(name):
- obstructive.append((self, name, info['node']))
+ if self._parent.resolve_property(name):
+ obstructive.append((self, name, info.node))
# Remove all declared variables from the "unreferenced" set; add all
# undeclared variables to the "undeclared" list.
for name, node in self._references:
- resolved = self.resolve_identifier(name)
+ resolved = self.resolve_property(name)
if resolved:
# Make sure this isn't an assignment.
if node.parent.kind in (tok.ASSIGN, tok.INC, tok.DEC) and \
node.node_index == 0 and \
node.parent.parent.kind == tok.SEMI:
continue
- unreferenced.pop((resolved[0], name), None)
+ unreferenced.pop((resolved.parent_scope, name), None)
else:
# with statements cannot have undeclared identifiers.
if not is_in_with_scope:
@@ -192,9 +200,9 @@
# Remove all variables that have been set as "unused".
for name, node in self._unused:
- resolved = self.resolve_identifier(name)
+ resolved = self.resolve_property(name)
if resolved:
- unreferenced.pop((resolved[0], name), None)
+ unreferenced.pop((resolved.parent_scope, name), None)
else:
undeclared.append((self, name, node))
@@ -221,7 +229,7 @@
class _Script:
def __init__(self):
self._imports = set()
- self.scope = Scope()
+ self.scope = ScopeObject(None, None, 'scope')
def importscript(self, script):
self._imports.add(script)
def hasglobal(self, name):
@@ -233,7 +241,7 @@
return
# Check this scope.
- if self.scope.get_identifier(name):
+ if self.scope.has_property(name):
return self
searched.add(self)
@@ -554,7 +562,7 @@
for ref_scope, name, node in identifier_warnings['unreferenced']:
# Ignore the outer scope.
if ref_scope != scope:
- type_ = ref_scope.get_identifier_type(name)
+ type_ = ref_scope.get_property_type(name)
if type_ == 'arg':
report_lint(node, 'unreferenced_argument', name=name)
elif type_ == 'function':
@@ -582,11 +590,11 @@
return onpush
def _warn_or_declare(scope, name, type_, node, report):
- parent_scope, other = scope.resolve_identifier(name) or (None, None)
- if other and parent_scope == scope:
+ property = scope.resolve_property(name)
+ if property and property.parent_scope == scope:
# Only warn about duplications in this scope.
# Other scopes will be checked later.
- if other.kind == tok.NAME and other.opcode == op.ARGNAME:
+ if property.node.kind == tok.NAME and property.node.opcode == op.ARGNAME:
report(node, 'var_hides_arg', name=name)
else:
report(node, 'redeclared_var', name=name)
@@ -617,7 +625,7 @@
_warn_or_declare(scopes[-1], node.fn_name, 'function', node, report)
self._push_scope(node)
for var_name in node.fn_args:
- if scopes[-1].get_identifier(var_name.atom):
+ if scopes[-1].has_property(var_name.atom):
report(var_name, 'duplicate_formal', name=var_name.atom)
scopes[-1].add_declaration(var_name.atom, var_name, 'arg')
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2016-12-23 20:47:17
|
Revision: 356
http://sourceforge.net/p/javascriptlint/code/356
Author: matthiasmiller
Date: 2016-12-23 20:47:15 +0000 (Fri, 23 Dec 2016)
Log Message:
-----------
Fix "conf" setting in unit tests.
Modified Paths:
--------------
trunk/javascriptlint/conf.py
Modified: trunk/javascriptlint/conf.py
===================================================================
--- trunk/javascriptlint/conf.py 2016-12-23 20:45:40 UTC (rev 355)
+++ trunk/javascriptlint/conf.py 2016-12-23 20:47:15 UTC (rev 356)
@@ -180,11 +180,13 @@
wants_parm = True
wants_dir = True
def __init__(self, conf):
+ self.value = None
self._conf = conf
def load(self, enabled, parm, dir):
if dir:
parm = os.path.join(dir, parm)
self._conf.loadfile(parm)
+ self.value = parm
class Conf:
def __init__(self):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2016-12-23 20:45:43
|
Revision: 355
http://sourceforge.net/p/javascriptlint/code/355
Author: matthiasmiller
Date: 2016-12-23 20:45:40 +0000 (Fri, 23 Dec 2016)
Log Message:
-----------
Fix name conflict with built-in module.
Modified Paths:
--------------
trunk/javascriptlint/conf.py
trunk/javascriptlint/lint.py
Added Paths:
-----------
trunk/javascriptlint/lintwarnings.py
Removed Paths:
-------------
trunk/javascriptlint/warnings.py
Modified: trunk/javascriptlint/conf.py
===================================================================
--- trunk/javascriptlint/conf.py 2014-10-27 22:25:27 UTC (rev 354)
+++ trunk/javascriptlint/conf.py 2016-12-23 20:45:40 UTC (rev 355)
@@ -5,7 +5,7 @@
import fs
import util
import version
-import warnings
+import lintwarnings
_DISABLED_WARNINGS = (
'block_without_braces',
@@ -16,8 +16,8 @@
def _getwarningsconf():
lines = []
- for name in sorted(warnings.warnings.keys()):
- message = warnings.warnings[name]
+ for name in sorted(lintwarnings.warnings.keys()):
+ message = lintwarnings.warnings[name]
sign = '+'
if name in _DISABLED_WARNINGS:
sign = '-'
@@ -207,7 +207,7 @@
'anon_no_return_value': BooleanSetting(True),
'decorate_function_name_warning': BooleanSetting(False),
}
- for name in warnings.warnings:
+ for name in lintwarnings.warnings:
self._settings[name] = BooleanSetting(True)
for warning in _DISABLED_WARNINGS:
self.loadline('-%s' % warning)
Modified: trunk/javascriptlint/lint.py
===================================================================
--- trunk/javascriptlint/lint.py 2014-10-27 22:25:27 UTC (rev 354)
+++ trunk/javascriptlint/lint.py 2016-12-23 20:45:40 UTC (rev 355)
@@ -7,8 +7,8 @@
import fs
import htmlparse
import jsparse
+import lintwarnings
import visitation
-import warnings
import unittest
import util
@@ -482,7 +482,7 @@
# Find all visitors and convert them into "onpush" callbacks that call "report"
visitors = {
- 'push': warnings.make_visitors(conf)
+ 'push': lintwarnings.make_visitors(conf)
}
for event in visitors:
for kind, callbacks in visitors[event].items():
@@ -516,11 +516,11 @@
def _lint_script_parts(script_parts, script_cache, lint_error, conf, import_callback):
def report_lint(node, errname, offset=0, **errargs):
- errdesc = warnings.format_error(errname, **errargs)
+ errdesc = lintwarnings.format_error(errname, **errargs)
_report(offset or node.start_offset, errname, errdesc, True)
def report_native(offset, errname, errargs):
- errdesc = warnings.format_error(errname, **errargs)
+ errdesc = lintwarnings.format_error(errname, **errargs)
_report(offset, errname, errdesc, False)
def _report(offset, errname, errdesc, require_key):
@@ -571,7 +571,7 @@
try:
ret = visitor(node)
assert ret is None, 'visitor should raise an exception, not return a value'
- except warnings.LintWarning, warning:
+ except lintwarnings.LintWarning, warning:
# TODO: This is ugly hardcoding to improve the error positioning of
# "missing_semicolon" errors.
if visitor.warning in ('missing_semicolon', 'missing_semicolon_for_lambda'):
Copied: trunk/javascriptlint/lintwarnings.py (from rev 354, trunk/javascriptlint/warnings.py)
===================================================================
--- trunk/javascriptlint/lintwarnings.py (rev 0)
+++ trunk/javascriptlint/lintwarnings.py 2016-12-23 20:45:40 UTC (rev 355)
@@ -0,0 +1,814 @@
+# vim: ts=4 sw=4 expandtab
+""" This module contains all the warnings. To add a new warning, define a
+function. Its name should be in lowercase and words should be separated by
+underscores.
+
+The function should be decorated with a @lookfor call specifying the nodes it
+wants to examine. The node names may be in the tok.KIND or (tok.KIND, op.OPCODE)
+format. To report a warning, the function should raise a LintWarning exception.
+
+For example:
+
+ @lookfor(tok.NODEKIND, (tok.NODEKIND, op.OPCODE))
+ def warning_name(node):
+ if questionable:
+ raise LintWarning(node)
+"""
+import itertools
+import re
+import sys
+import types
+
+import util
+import visitation
+
+from jsengine.parser import kind as tok
+from jsengine.parser import op
+
+_ALL_TOKENS = tok.__dict__.values()
+
+def _get_assigned_lambda(node):
+ """ Given a node "x = function() {}", returns "function() {}".
+ """
+ value = None
+ if node.kind == tok.SEMI:
+ assign_node, = node.kids
+ if assign_node and assign_node.kind == tok.ASSIGN:
+ ignored, value = assign_node.kids
+ elif node.kind == tok.VAR:
+ variables = node.kids
+ if variables:
+ value, = variables[-1].kids
+
+ if value and value.kind == tok.FUNCTION and value.opcode == op.ANONFUNOBJ:
+ return value
+
+# TODO: document inspect, node:opcode, etc
+
+warnings = {
+ 'comparison_type_conv': 'comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)',
+ 'default_not_at_end': 'the default case is not at the end of the switch statement',
+ 'duplicate_case_in_switch': 'duplicate case in switch statement',
+ 'missing_default_case': 'missing default case in switch statement',
+ 'with_statement': 'with statement hides undeclared variables; use temporary variable instead',
+ 'useless_comparison': 'useless comparison; comparing identical expressions',
+ 'use_of_label': 'use of label',
+ 'misplaced_regex': 'regular expressions should be preceded by a left parenthesis, assignment, colon, or comma',
+ 'assign_to_function_call': 'assignment to a function call',
+ 'equal_as_assign': 'test for equality (==) mistyped as assignment (=)?',
+ 'ambiguous_else_stmt': 'the else statement could be matched with one of multiple if statements (use curly braces to indicate intent',
+ 'block_without_braces': 'block statement without curly braces',
+ 'ambiguous_nested_stmt': 'block statements containing block statements should use curly braces to resolve ambiguity',
+ 'inc_dec_within_stmt': 'increment (++) and decrement (--) operators used as part of greater statement',
+ 'comma_separated_stmts': 'multiple statements separated by commas (use semicolons?)',
+ 'empty_statement': 'empty statement or extra semicolon',
+ 'missing_break': 'missing break statement',
+ 'missing_break_for_last_case': 'missing break statement for last case in switch',
+ 'multiple_plus_minus': 'unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs',
+ 'useless_assign': 'useless assignment',
+ 'unreachable_code': 'unreachable code',
+ 'meaningless_block': 'meaningless block; curly braces have no impact',
+ 'useless_void': 'use of the void type may be unnecessary (void is always undefined)',
+ 'parseint_missing_radix': 'parseInt missing radix parameter',
+ 'leading_decimal_point': 'leading decimal point may indicate a number or an object member',
+ 'trailing_decimal_point': 'trailing decimal point may indicate a number or an object member',
+ 'octal_number': 'leading zeros make an octal number',
+ 'trailing_comma': 'extra comma is not recommended in object initializers',
+ 'trailing_comma_in_array': 'extra comma is not recommended in array initializers',
+ 'useless_quotes': 'the quotation marks are unnecessary',
+ 'mismatch_ctrl_comments': 'mismatched control comment; "ignore" and "end" control comments must have a one-to-one correspondence',
+ 'redeclared_var': 'redeclaration of {name}',
+ 'undeclared_identifier': 'undeclared identifier: {name}',
+ 'unreferenced_argument': 'argument declared but never referenced: {name}',
+ 'unreferenced_function': 'function is declared but never referenced: {name}',
+ 'unreferenced_variable': 'variable is declared but never referenced: {name}',
+ 'jsl_cc_not_understood': 'couldn\'t understand control comment using /*jsl:keyword*/ syntax',
+ 'nested_comment': 'nested comment',
+ 'legacy_cc_not_understood': 'couldn\'t understand control comment using /*@keyword@*/ syntax',
+ 'var_hides_arg': 'variable {name} hides argument',
+ 'identifier_hides_another': 'identifer {name} hides an identifier in a parent scope',
+ 'duplicate_formal': 'duplicate formal argument {name}',
+ 'missing_semicolon': 'missing semicolon',
+ 'missing_semicolon_for_lambda': 'missing semicolon for lambda assignment',
+ 'ambiguous_newline': 'unexpected end of line; it is ambiguous whether these lines are part of the same statement',
+ 'missing_option_explicit': 'the "option explicit" control comment is missing',
+ 'partial_option_explicit': 'the "option explicit" control comment, if used, must be in the first script tag',
+ 'dup_option_explicit': 'duplicate "option explicit" control comment',
+ 'invalid_fallthru': 'unexpected "fallthru" control comment',
+ 'invalid_pass': 'unexpected "pass" control comment',
+ 'want_assign_or_call': 'expected an assignment or function call',
+ 'no_return_value': 'function {name} does not always return a value',
+ 'anon_no_return_value': 'anonymous function does not always return value',
+ 'unsupported_version': 'JavaScript {version} is not supported',
+ 'incorrect_version': 'Expected /*jsl:content-type*/ control comment. The script was parsed with the wrong version.',
+ 'for_in_missing_identifier': 'for..in should have identifier on left side',
+ 'misplaced_function': 'unconventional use of function expression',
+ 'function_name_missing': 'anonymous function should be named to match property name {name}',
+ 'function_name_mismatch': 'function name {fn_name} does not match property name {prop_name}',
+ 'trailing_whitespace': 'trailing whitespace',
+}
+
+errors = {
+ 'e4x_deprecated': 'e4x is deprecated',
+ 'semi_before_stmnt': 'missing semicolon before statement',
+ 'syntax_error': 'syntax error',
+ 'expected_tok': 'expected token: {token}',
+ 'unexpected_char': 'unexpected character: {char}',
+ 'unexpected_eof': 'unexpected end of file',
+ 'io_error': '{error}',
+}
+
+def format_error(errname, **errargs):
+ if errname in errors:
+ errdesc = errors[errname]
+ else:
+ errdesc = warnings[errname]
+
+ try:
+ keyword = re.compile(r"{(\w+)}")
+ errdesc = keyword.sub(lambda match: errargs[match.group(1)], errdesc)
+ except (TypeError, KeyError):
+ raise KeyError('Invalid keyword in error %s: %s' % (errname, errdesc))
+ return errdesc
+
+_visitors = []
+def lookfor(*args):
+ def decorate(fn):
+ fn.warning = fn.func_name.rstrip('_')
+ assert fn.warning in warnings, 'Missing warning description: %s' % fn.warning
+
+ for arg in args:
+ _visitors.append((arg, fn))
+ return decorate
+
+_visitor_classes = []
+def lookfor_class(*args):
+ def decorate(cls):
+ # Convert the class name to camel case
+ camelcase = re.sub('([A-Z])', r'_\1', cls.__name__).lower().lstrip('_')
+
+ cls.warning = camelcase.rstrip('_')
+ assert cls.warning in warnings, \
+ 'Missing warning description: %s' % cls.warning
+
+ for arg in args:
+ _visitor_classes.append((arg, cls))
+ return decorate
+
+class LintWarning(Exception):
+ def __init__(self, node, **errargs):
+ self.node = node
+ self.errargs = errargs
+
+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
+
+def _get_exit_points(node):
+ """ Returns a set of exit points, which may be:
+ * None, indicating a code path with no specific exit point.
+ * a node of type tok.BREAK, tok.RETURN, tok.THROW.
+ """
+ if node.kind == tok.LC:
+ exit_points = set([None])
+ for kid in node.kids:
+ if kid:
+ # Merge in the kid's exit points.
+ kid_exit_points = _get_exit_points(kid)
+ exit_points |= kid_exit_points
+
+ # Stop if the kid always exits.
+ if not None in kid_exit_points:
+ exit_points.discard(None)
+ break
+ 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_)
+ else:
+ exit_points.add(None)
+ elif node.kind == tok.SWITCH:
+ exit_points = set([None])
+
+ 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
+
+ # Correct the "None" exit point.
+ exit_points.remove(None)
+
+ # Convert "break" into None
+ def break_to_none(node):
+ if node and node.kind != tok.BREAK:
+ return node
+ exit_points = set(map(break_to_none, exit_points))
+
+ # Check if the switch had a default case
+ if not switch_has_default:
+ exit_points.add(None)
+
+ # Check if the final case statement had a fallthru
+ if switch_has_final_fallthru:
+ exit_points.add(None)
+ elif node.kind == tok.BREAK:
+ exit_points = set([node])
+ elif node.kind == tok.CONTINUE:
+ exit_points = set([node])
+ elif node.kind == tok.WITH:
+ exit_points = _get_exit_points(node.kids[-1])
+ elif node.kind == tok.RETURN:
+ exit_points = set([node])
+ elif node.kind == tok.THROW:
+ exit_points = set([node])
+ elif node.kind == tok.TRY:
+ try_, catch_, finally_ = node.kids
+
+ exit_points = _get_exit_points(try_)
+
+ if catch_:
+ assert catch_.kind == tok.RESERVED
+ catch_, = catch_.kids
+ assert catch_.kind == tok.LEXICALSCOPE
+ catch_, = catch_.kids
+ assert catch_.kind == tok.CATCH
+ ignored, ignored, catch_ = catch_.kids
+ assert catch_.kind == tok.LC
+
+ exit_points |= _get_exit_points(catch_)
+
+ if finally_:
+ finally_exit_points = _get_exit_points(finally_)
+ if None in finally_exit_points:
+ # The finally statement does not add a missing exit point.
+ finally_exit_points.remove(None)
+ else:
+ # If the finally statement always returns, the other
+ # exit points are irrelevant.
+ if None in exit_points:
+ exit_points.remove(None)
+
+ exit_points |= finally_exit_points
+
+ else:
+ exit_points = set([None])
+
+ return exit_points
+
+def _loop_has_unreachable_condition(node):
+ for exit_point in _get_exit_points(node):
+ if exit_point is None:
+ return False
+ if exit_point.kind == tok.CONTINUE:
+ return False
+ return True
+
+@lookfor((tok.EQOP, op.EQ))
+def comparison_type_conv(node):
+ for kid in node.kids:
+ if kid.kind == tok.PRIMARY and kid.opcode in (op.NULL, op.TRUE, op.FALSE):
+ raise LintWarning(kid)
+ if kid.kind == tok.NUMBER and not kid.dval:
+ raise LintWarning(kid)
+ if kid.kind == tok.STRING and not kid.atom:
+ raise LintWarning(kid)
+
+@lookfor(tok.DEFAULT)
+def default_not_at_end(node):
+ siblings = node.parent.kids
+ if node.node_index != len(siblings)-1:
+ raise LintWarning(siblings[node.node_index+1])
+
+@lookfor(tok.CASE)
+def duplicate_case_in_switch(node):
+ # Only look at previous siblings
+ siblings = node.parent.kids
+ siblings = siblings[:node.node_index]
+ # Compare values (first kid)
+ node_value = node.kids[0]
+ for sibling in siblings:
+ if sibling.kind == tok.CASE:
+ sibling_value = sibling.kids[0]
+ if node_value.is_equivalent(sibling_value, True):
+ raise LintWarning(node)
+
+@lookfor(tok.SWITCH)
+def missing_default_case(node):
+ value, cases = node.kids
+ for case in cases.kids:
+ if case.kind == tok.DEFAULT:
+ return
+ raise LintWarning(node)
+
+@lookfor(tok.WITH)
+def with_statement(node):
+ raise LintWarning(node)
+
+@lookfor(tok.EQOP, tok.RELOP)
+def useless_comparison(node):
+ for lvalue, rvalue in itertools.combinations(node.kids, 2):
+ if lvalue.is_equivalent(rvalue):
+ raise LintWarning(node)
+
+@lookfor((tok.COLON, op.NAME))
+def use_of_label(node):
+ raise LintWarning(node)
+
+@lookfor((tok.OBJECT, op.REGEXP))
+def misplaced_regex(node):
+ if node.parent.kind == tok.NAME and node.parent.opcode == op.SETNAME:
+ return # Allow in var statements
+ if node.parent.kind == tok.ASSIGN and node.parent.opcode == op.NOP:
+ return # Allow in assigns
+ if node.parent.kind == tok.COLON and node.parent.parent.kind == tok.RC:
+ return # Allow in object literals
+ if node.parent.kind == tok.LP and node.parent.opcode == op.CALL:
+ return # Allow in parameters
+ if node.parent.kind == tok.DOT and node.parent.opcode == op.GETPROP:
+ return # Allow in /re/.property
+ if node.parent.kind == tok.RETURN:
+ return # Allow for return values
+ raise LintWarning(node)
+
+@lookfor(tok.ASSIGN)
+def assign_to_function_call(node):
+ kid = node.kids[0]
+ # Unpack parens.
+ while kid.kind == tok.RP:
+ kid, = kid.kids
+ if kid.kind == tok.LP:
+ raise LintWarning(node)
+
+@lookfor((tok.ASSIGN, None))
+def equal_as_assign(node):
+ # Allow in VAR statements.
+ if node.parent.parent and node.parent.parent.kind == tok.VAR:
+ return
+
+ if not node.parent.kind in (tok.SEMI, tok.RESERVED, tok.RP, tok.COMMA,
+ tok.ASSIGN):
+ raise LintWarning(node)
+
+@lookfor(tok.IF)
+def ambiguous_else_stmt(node):
+ # Only examine this node if it has an else statement.
+ condition, if_, else_ = node.kids
+ if not else_:
+ return
+
+ tmp = node
+ while tmp:
+ # Curly braces always clarify if statements.
+ if tmp.kind == tok.LC:
+ return
+ # Else is only ambiguous in the first branch of an if statement.
+ if tmp.parent.kind == tok.IF and tmp.node_index == 1:
+ raise LintWarning(else_)
+ tmp = tmp.parent
+
+@lookfor(tok.IF, tok.WHILE, tok.DO, tok.FOR, tok.WITH)
+def block_without_braces(node):
+ if node.kids[1].kind != tok.LC:
+ raise LintWarning(node.kids[1])
+
+_block_nodes = (tok.IF, tok.WHILE, tok.DO, tok.FOR, tok.WITH)
+@lookfor(*_block_nodes)
+def ambiguous_nested_stmt(node):
+ # Ignore "else if"
+ if node.kind == tok.IF and node.node_index == 2 and node.parent.kind == tok.IF:
+ return
+
+ # If the parent is a block, it means a block statement
+ # was inside a block statement without clarifying curlies.
+ # (Otherwise, the node type would be tok.LC.)
+ if node.parent.kind in _block_nodes:
+ raise LintWarning(node)
+
+@lookfor(tok.INC, tok.DEC)
+def inc_dec_within_stmt(node):
+ if node.parent.kind == tok.SEMI:
+ return
+
+ # Allow within the third part of the "for"
+ tmp = node
+ while tmp and tmp.parent and tmp.parent.kind == tok.COMMA:
+ tmp = tmp.parent
+ if tmp and tmp.node_index == 2 and \
+ tmp.parent.kind == tok.RESERVED and \
+ tmp.parent.parent.kind == tok.FOR:
+ return
+
+ raise LintWarning(node)
+
+@lookfor(tok.COMMA)
+def comma_separated_stmts(node):
+ # Allow within the first and third part of "for(;;)"
+ if _get_branch_in_for(node) in (0, 2):
+ return
+ # This is an array
+ if node.parent.kind == tok.RB:
+ return
+ raise LintWarning(node)
+
+@lookfor(tok.SEMI)
+def empty_statement(node):
+ if not node.kids[0]:
+ raise LintWarning(node)
+@lookfor(tok.LC)
+def empty_statement_(node):
+ if node.kids:
+ return
+ # Ignore the outermost block.
+ if not node.parent:
+ return
+ # Some empty blocks are meaningful.
+ if node.parent.kind in (tok.CATCH, tok.CASE, tok.DEFAULT, tok.SWITCH, tok.FUNCTION):
+ return
+ raise LintWarning(node)
+
+@lookfor(tok.CASE, tok.DEFAULT)
+def missing_break(node):
+ # The last item is handled separately
+ if node.node_index == len(node.parent.kids)-1:
+ return
+ case_contents = node.kids[1]
+ assert case_contents.kind == tok.LC
+ # Ignore empty case statements
+ if not case_contents.kids:
+ return
+ if None in _get_exit_points(case_contents):
+ # Show the warning on the *next* node.
+ raise LintWarning(node.parent.kids[node.node_index+1])
+
+@lookfor(tok.CASE, tok.DEFAULT)
+def missing_break_for_last_case(node):
+ if node.node_index < len(node.parent.kids)-1:
+ return
+ case_contents = node.kids[1]
+ assert case_contents.kind == tok.LC
+ if None in _get_exit_points(case_contents):
+ raise LintWarning(node)
+
+@lookfor(tok.INC)
+def multiple_plus_minus(node):
+ if node.node_index == 0 and node.parent.kind == tok.PLUS:
+ raise LintWarning(node)
+@lookfor(tok.DEC)
+def multiple_plus_minus_(node):
+ if node.node_index == 0 and node.parent.kind == tok.MINUS:
+ raise LintWarning(node)
+
+@lookfor((tok.NAME, op.SETNAME))
+def useless_assign(node):
+ if node.parent.kind == tok.ASSIGN:
+ assert node.node_index == 0
+ value = node.parent.kids[1]
+ elif node.parent.kind == tok.VAR:
+ value = node.kids[0]
+ if value and value.kind == tok.NAME and node.atom == value.atom:
+ raise LintWarning(node)
+
+@lookfor(tok.BREAK, tok.CONTINUE, tok.RETURN, tok.THROW)
+def unreachable_code(node):
+ if node.parent.kind == tok.LC:
+ for sibling in node.parent.kids[node.node_index+1:]:
+ if sibling.kind == tok.VAR:
+ # Look for a variable assignment
+ for variable in sibling.kids:
+ value, = variable.kids
+ if value:
+ raise LintWarning(value)
+ elif sibling.kind == tok.FUNCTION:
+ # Functions are always declared.
+ pass
+ else:
+ raise LintWarning(sibling)
+
+@lookfor(tok.FOR)
+def unreachable_code_(node):
+ # Warn if the for loop always exits.
+ preamble, code = node.kids
+ if preamble.kind == tok.RESERVED:
+ pre, condition, post = preamble.kids
+ if post:
+ if _loop_has_unreachable_condition(code):
+ raise LintWarning(post)
+
+@lookfor(tok.DO)
+def unreachable_code__(node):
+ # Warn if the do..while loop always exits.
+ code, condition = node.kids
+ if _loop_has_unreachable_condition(code):
+ raise LintWarning(condition)
+
+#TODO: @lookfor(tok.IF)
+def meaningless_block(node):
+ condition, if_, else_ = node.kids
+ if condition.kind == tok.PRIMARY and condition.opcode in (op.TRUE, op.FALSE, op.NULL):
+ raise LintWarning(condition)
+#TODO: @lookfor(tok.WHILE)
+def meaningless_blocK_(node):
+ condition = node.kids[0]
+ if condition.kind == tok.PRIMARY and condition.opcode in (op.FALSE, op.NULL):
+ raise LintWarning(condition)
+@lookfor(tok.LC)
+def meaningless_block__(node):
+ if node.parent and node.parent.kind == tok.LC:
+ raise LintWarning(node)
+
+@lookfor((tok.UNARYOP, op.VOID))
+def useless_void(node):
+ raise LintWarning(node)
+
+@lookfor((tok.LP, op.CALL))
+def parseint_missing_radix(node):
+ if node.kids[0].kind == tok.NAME and node.kids[0].atom == 'parseInt' and len(node.kids) <= 2:
+ raise LintWarning(node)
+
+@lookfor(tok.NUMBER)
+def leading_decimal_point(node):
+ if node.atom.startswith('.'):
+ raise LintWarning(node)
+
+@lookfor(tok.NUMBER)
+def trailing_decimal_point(node):
+ if node.parent.kind == tok.DOT:
+ raise LintWarning(node)
+ if node.atom.endswith('.'):
+ raise LintWarning(node)
+
+_octal_regexp = re.compile('^0[0-9]')
+@lookfor(tok.NUMBER)
+def octal_number(node):
+ if _octal_regexp.match(node.atom):
+ raise LintWarning(node)
+
+@lookfor(tok.RC)
+def trailing_comma(node):
+ if node.end_comma:
+ # Warn on the last value in the dictionary.
+ last_item = node.kids[-1]
+ assert last_item.kind == tok.COLON
+ key, value = last_item.kids
+ raise LintWarning(value)
+
+@lookfor(tok.RB)
+def trailing_comma_in_array(node):
+ if node.end_comma:
+ # Warn on the last value in the array.
+ raise LintWarning(node.kids[-1])
+
+@lookfor(tok.STRING)
+def useless_quotes(node):
+ if node.node_index == 0 and node.parent.kind == tok.COLON:
+ # Only warn if the quotes could safely be removed.
+ if util.isidentifier(node.atom):
+ raise LintWarning(node)
+
+@lookfor(tok.SEMI)
+def want_assign_or_call(node):
+ child, = node.kids
+ # Ignore empty statements.
+ if not child:
+ return
+ # NOTE: Don't handle comma-separated statements.
+ if child.kind in (tok.ASSIGN, tok.INC, tok.DEC, tok.DELETE, tok.COMMA):
+ return
+ if child.kind == tok.YIELD:
+ return
+ # Ignore function calls.
+ if child.kind == tok.LP and child.opcode == op.CALL:
+ return
+ # Allow new function() { } as statements.
+ if child.kind == tok.NEW:
+ # The first kid is the constructor, followed by its arguments.
+ grandchild = child.kids[0]
+ if grandchild.kind == tok.FUNCTION:
+ return
+ raise LintWarning(child)
+
+def _check_return_value(node):
+ name = node.fn_name or '(anonymous function)'
+
+ def is_return_with_val(node):
+ return node and node.kind == tok.RETURN and node.kids[0]
+ def is_return_without_val(node):
+ return node and node.kind == tok.RETURN and not node.kids[0]
+
+ node, = node.kids
+ assert node.kind == tok.LC
+
+ exit_points = _get_exit_points(node)
+ if filter(is_return_with_val, exit_points):
+ # If the function returns a value, find all returns without a value.
+ returns = filter(is_return_without_val, exit_points)
+ returns.sort(key=lambda node: node.start_offset)
+ if returns:
+ raise LintWarning(returns[0], name=name)
+ # Warn if the function sometimes exits naturally.
+ if None in exit_points:
+ raise LintWarning(node, name=name)
+
+@lookfor(tok.FUNCTION)
+def no_return_value(node):
+ if node.fn_name:
+ _check_return_value(node)
+
+@lookfor(tok.FUNCTION)
+def anon_no_return_value(node):
+ if not node.fn_name:
+ _check_return_value(node)
+
+@lookfor((tok.FOR, op.FORIN))
+def for_in_missing_identifier(node):
+ assert node.kids[0].kind == tok.IN
+ left, right = node.kids[0].kids
+ if not left.kind in (tok.VAR, tok.NAME):
+ raise LintWarning(left)
+
+@lookfor(tok.FUNCTION)
+def misplaced_function(node):
+ # Ignore function statements.
+ if node.opcode in (None, op.CLOSURE):
+ return
+
+ # Ignore parens.
+ parent = node.parent
+ while parent.kind == tok.RP:
+ parent = parent.parent
+
+ # Allow x = x || ...
+ if parent.kind == tok.OR and len(parent.kids) == 2 and \
+ node is parent.kids[-1]:
+ parent = parent.parent
+
+ if parent.kind == tok.NAME and parent.opcode == op.SETNAME:
+ return # Allow in var statements
+ if parent.kind == tok.ASSIGN and parent.opcode == op.NOP:
+ return # Allow in assigns
+ if parent.kind == tok.COLON and parent.parent.kind == tok.RC:
+ return # Allow in object literals
+ if parent.kind == tok.LP and parent.opcode in (op.CALL, op.SETCALL):
+ return # Allow in parameters
+ if parent.kind == tok.RETURN:
+ return # Allow for return values
+ if parent.kind == tok.NEW:
+ return # Allow as constructors
+ raise LintWarning(node)
+
+def _get_function_property_name(node):
+ # Ignore function statements.
+ if node.opcode in (None, op.CLOSURE):
+ return
+
+ # Ignore parens.
+ parent = node.parent
+ while parent.kind == tok.RP:
+ parent = parent.parent
+
+ # Allow x = x || ...
+ if parent.kind == tok.OR and len(parent.kids) == 2 and \
+ node is parent.kids[-1]:
+ parent = parent.parent
+
+ # Var assignment.
+ if parent.kind == tok.NAME and parent.opcode == op.SETNAME:
+ return parent.atom
+
+ # Assignment.
+ if parent.kind == tok.ASSIGN and parent.opcode == op.NOP:
+ if parent.kids[0].kind == tok.NAME and \
+ parent.kids[0].opcode == op.SETNAME:
+ return parent.kids[0].atom
+ if parent.kids[0].kind == tok.DOT and \
+ parent.kids[0].opcode == op.SETPROP:
+ return parent.kids[0].atom
+ return '<error>'
+
+ # Object literal.
+ if parent.kind == tok.COLON and parent.parent.kind == tok.RC:
+ return parent.kids[0].atom
+
+def _get_expected_function_name(node, decorate):
+ name = _get_function_property_name(node)
+ if name and decorate:
+ return '__%s' % name
+ return name
+
+@lookfor_class(tok.FUNCTION)
+class FunctionNameMissing(object):
+ def __init__(self, conf):
+ self._decorate = conf['decorate_function_name_warning']
+
+ def __call__(self, node):
+ if node.fn_name:
+ return
+
+ expected_name = _get_expected_function_name(node, self._decorate)
+ if not expected_name is None:
+ raise LintWarning(node, name=expected_name)
+
+@lookfor_class(tok.FUNCTION)
+class FunctionNameMismatch(object):
+ def __init__(self, conf):
+ self._decorate = conf['decorate_function_name_warning']
+
+ def __call__(self, node):
+ if not node.fn_name:
+ return
+
+ expected_name = _get_expected_function_name(node, self._decorate)
+ if expected_name is None:
+ return
+
+ if expected_name != node.fn_name:
+ raise LintWarning(node, fn_name=node.fn_name,
+ prop_name=expected_name)
+
+@lookfor()
+def mismatch_ctrl_comments(node):
+ pass
+
+@lookfor()
+def redeclared_var(node):
+ pass
+
+@lookfor()
+def undeclared_identifier(node):
+ pass
+
+@lookfor()
+def jsl_cc_not_understood(node):
+ pass
+
+@lookfor()
+def nested_comment(node):
+ pass
+
+@lookfor()
+def legacy_cc_not_understood(node):
+ pass
+
+@lookfor()
+def var_hides_arg(node):
+ pass
+
+@lookfor()
+def duplicate_formal(node):
+ pass
+
+@lookfor(*_ALL_TOKENS)
+def missing_semicolon(node):
+ if node.no_semi:
+ if not _get_assigned_lambda(node):
+ raise LintWarning(node)
+
+@lookfor(*_ALL_TOKENS)
+def missing_semicolon_for_lambda(node):
+ if node.no_semi:
+ # spidermonkey sometimes returns incorrect positions for var
+ # statements, so use the position of the lambda instead.
+ lambda_ = _get_assigned_lambda(node)
+ if lambda_:
+ raise LintWarning(lambda_)
+
+@lookfor()
+def ambiguous_newline(node):
+ pass
+
+@lookfor()
+def missing_option_explicit(node):
+ pass
+
+@lookfor()
+def partial_option_explicit(node):
+ pass
+
+@lookfor()
+def dup_option_explicit(node):
+ pass
+
+def make_visitors(conf):
+ all_visitors = list(_visitors)
+ for kind, klass in _visitor_classes:
+ all_visitors.append((kind, klass(conf=conf)))
+
+ visitors = {}
+ for kind, func in all_visitors:
+ try:
+ visitors[kind].append(func)
+ except KeyError:
+ visitors[kind] = [func]
+ return visitors
+
Deleted: trunk/javascriptlint/warnings.py
===================================================================
--- trunk/javascriptlint/warnings.py 2014-10-27 22:25:27 UTC (rev 354)
+++ trunk/javascriptlint/warnings.py 2016-12-23 20:45:40 UTC (rev 355)
@@ -1,814 +0,0 @@
-# vim: ts=4 sw=4 expandtab
-""" This module contains all the warnings. To add a new warning, define a
-function. Its name should be in lowercase and words should be separated by
-underscores.
-
-The function should be decorated with a @lookfor call specifying the nodes it
-wants to examine. The node names may be in the tok.KIND or (tok.KIND, op.OPCODE)
-format. To report a warning, the function should raise a LintWarning exception.
-
-For example:
-
- @lookfor(tok.NODEKIND, (tok.NODEKIND, op.OPCODE))
- def warning_name(node):
- if questionable:
- raise LintWarning(node)
-"""
-import itertools
-import re
-import sys
-import types
-
-import util
-import visitation
-
-from jsengine.parser import kind as tok
-from jsengine.parser import op
-
-_ALL_TOKENS = tok.__dict__.values()
-
-def _get_assigned_lambda(node):
- """ Given a node "x = function() {}", returns "function() {}".
- """
- value = None
- if node.kind == tok.SEMI:
- assign_node, = node.kids
- if assign_node and assign_node.kind == tok.ASSIGN:
- ignored, value = assign_node.kids
- elif node.kind == tok.VAR:
- variables = node.kids
- if variables:
- value, = variables[-1].kids
-
- if value and value.kind == tok.FUNCTION and value.opcode == op.ANONFUNOBJ:
- return value
-
-# TODO: document inspect, node:opcode, etc
-
-warnings = {
- 'comparison_type_conv': 'comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)',
- 'default_not_at_end': 'the default case is not at the end of the switch statement',
- 'duplicate_case_in_switch': 'duplicate case in switch statement',
- 'missing_default_case': 'missing default case in switch statement',
- 'with_statement': 'with statement hides undeclared variables; use temporary variable instead',
- 'useless_comparison': 'useless comparison; comparing identical expressions',
- 'use_of_label': 'use of label',
- 'misplaced_regex': 'regular expressions should be preceded by a left parenthesis, assignment, colon, or comma',
- 'assign_to_function_call': 'assignment to a function call',
- 'equal_as_assign': 'test for equality (==) mistyped as assignment (=)?',
- 'ambiguous_else_stmt': 'the else statement could be matched with one of multiple if statements (use curly braces to indicate intent',
- 'block_without_braces': 'block statement without curly braces',
- 'ambiguous_nested_stmt': 'block statements containing block statements should use curly braces to resolve ambiguity',
- 'inc_dec_within_stmt': 'increment (++) and decrement (--) operators used as part of greater statement',
- 'comma_separated_stmts': 'multiple statements separated by commas (use semicolons?)',
- 'empty_statement': 'empty statement or extra semicolon',
- 'missing_break': 'missing break statement',
- 'missing_break_for_last_case': 'missing break statement for last case in switch',
- 'multiple_plus_minus': 'unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs',
- 'useless_assign': 'useless assignment',
- 'unreachable_code': 'unreachable code',
- 'meaningless_block': 'meaningless block; curly braces have no impact',
- 'useless_void': 'use of the void type may be unnecessary (void is always undefined)',
- 'parseint_missing_radix': 'parseInt missing radix parameter',
- 'leading_decimal_point': 'leading decimal point may indicate a number or an object member',
- 'trailing_decimal_point': 'trailing decimal point may indicate a number or an object member',
- 'octal_number': 'leading zeros make an octal number',
- 'trailing_comma': 'extra comma is not recommended in object initializers',
- 'trailing_comma_in_array': 'extra comma is not recommended in array initializers',
- 'useless_quotes': 'the quotation marks are unnecessary',
- 'mismatch_ctrl_comments': 'mismatched control comment; "ignore" and "end" control comments must have a one-to-one correspondence',
- 'redeclared_var': 'redeclaration of {name}',
- 'undeclared_identifier': 'undeclared identifier: {name}',
- 'unreferenced_argument': 'argument declared but never referenced: {name}',
- 'unreferenced_function': 'function is declared but never referenced: {name}',
- 'unreferenced_variable': 'variable is declared but never referenced: {name}',
- 'jsl_cc_not_understood': 'couldn\'t understand control comment using /*jsl:keyword*/ syntax',
- 'nested_comment': 'nested comment',
- 'legacy_cc_not_understood': 'couldn\'t understand control comment using /*@keyword@*/ syntax',
- 'var_hides_arg': 'variable {name} hides argument',
- 'identifier_hides_another': 'identifer {name} hides an identifier in a parent scope',
- 'duplicate_formal': 'duplicate formal argument {name}',
- 'missing_semicolon': 'missing semicolon',
- 'missing_semicolon_for_lambda': 'missing semicolon for lambda assignment',
- 'ambiguous_newline': 'unexpected end of line; it is ambiguous whether these lines are part of the same statement',
- 'missing_option_explicit': 'the "option explicit" control comment is missing',
- 'partial_option_explicit': 'the "option explicit" control comment, if used, must be in the first script tag',
- 'dup_option_explicit': 'duplicate "option explicit" control comment',
- 'invalid_fallthru': 'unexpected "fallthru" control comment',
- 'invalid_pass': 'unexpected "pass" control comment',
- 'want_assign_or_call': 'expected an assignment or function call',
- 'no_return_value': 'function {name} does not always return a value',
- 'anon_no_return_value': 'anonymous function does not always return value',
- 'unsupported_version': 'JavaScript {version} is not supported',
- 'incorrect_version': 'Expected /*jsl:content-type*/ control comment. The script was parsed with the wrong version.',
- 'for_in_missing_identifier': 'for..in should have identifier on left side',
- 'misplaced_function': 'unconventional use of function expression',
- 'function_name_missing': 'anonymous function should be named to match property name {name}',
- 'function_name_mismatch': 'function name {fn_name} does not match property name {prop_name}',
- 'trailing_whitespace': 'trailing whitespace',
-}
-
-errors = {
- 'e4x_deprecated': 'e4x is deprecated',
- 'semi_before_stmnt': 'missing semicolon before statement',
- 'syntax_error': 'syntax error',
- 'expected_tok': 'expected token: {token}',
- 'unexpected_char': 'unexpected character: {char}',
- 'unexpected_eof': 'unexpected end of file',
- 'io_error': '{error}',
-}
-
-def format_error(errname, **errargs):
- if errname in errors:
- errdesc = errors[errname]
- else:
- errdesc = warnings[errname]
-
- try:
- keyword = re.compile(r"{(\w+)}")
- errdesc = keyword.sub(lambda match: errargs[match.group(1)], errdesc)
- except (TypeError, KeyError):
- raise KeyError('Invalid keyword in error %s: %s' % (errname, errdesc))
- return errdesc
-
-_visitors = []
-def lookfor(*args):
- def decorate(fn):
- fn.warning = fn.func_name.rstrip('_')
- assert fn.warning in warnings, 'Missing warning description: %s' % fn.warning
-
- for arg in args:
- _visitors.append((arg, fn))
- return decorate
-
-_visitor_classes = []
-def lookfor_class(*args):
- def decorate(cls):
- # Convert the class name to camel case
- camelcase = re.sub('([A-Z])', r'_\1', cls.__name__).lower().lstrip('_')
-
- cls.warning = camelcase.rstrip('_')
- assert cls.warning in warnings, \
- 'Missing warning description: %s' % cls.warning
-
- for arg in args:
- _visitor_classes.append((arg, cls))
- return decorate
-
-class LintWarning(Exception):
- def __init__(self, node, **errargs):
- self.node = node
- self.errargs = errargs
-
-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
-
-def _get_exit_points(node):
- """ Returns a set of exit points, which may be:
- * None, indicating a code path with no specific exit point.
- * a node of type tok.BREAK, tok.RETURN, tok.THROW.
- """
- if node.kind == tok.LC:
- exit_points = set([None])
- for kid in node.kids:
- if kid:
- # Merge in the kid's exit points.
- kid_exit_points = _get_exit_points(kid)
- exit_points |= kid_exit_points
-
- # Stop if the kid always exits.
- if not None in kid_exit_points:
- exit_points.discard(None)
- break
- 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_)
- else:
- exit_points.add(None)
- elif node.kind == tok.SWITCH:
- exit_points = set([None])
-
- 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
-
- # Correct the "None" exit point.
- exit_points.remove(None)
-
- # Convert "break" into None
- def break_to_none(node):
- if node and node.kind != tok.BREAK:
- return node
- exit_points = set(map(break_to_none, exit_points))
-
- # Check if the switch had a default case
- if not switch_has_default:
- exit_points.add(None)
-
- # Check if the final case statement had a fallthru
- if switch_has_final_fallthru:
- exit_points.add(None)
- elif node.kind == tok.BREAK:
- exit_points = set([node])
- elif node.kind == tok.CONTINUE:
- exit_points = set([node])
- elif node.kind == tok.WITH:
- exit_points = _get_exit_points(node.kids[-1])
- elif node.kind == tok.RETURN:
- exit_points = set([node])
- elif node.kind == tok.THROW:
- exit_points = set([node])
- elif node.kind == tok.TRY:
- try_, catch_, finally_ = node.kids
-
- exit_points = _get_exit_points(try_)
-
- if catch_:
- assert catch_.kind == tok.RESERVED
- catch_, = catch_.kids
- assert catch_.kind == tok.LEXICALSCOPE
- catch_, = catch_.kids
- assert catch_.kind == tok.CATCH
- ignored, ignored, catch_ = catch_.kids
- assert catch_.kind == tok.LC
-
- exit_points |= _get_exit_points(catch_)
-
- if finally_:
- finally_exit_points = _get_exit_points(finally_)
- if None in finally_exit_points:
- # The finally statement does not add a missing exit point.
- finally_exit_points.remove(None)
- else:
- # If the finally statement always returns, the other
- # exit points are irrelevant.
- if None in exit_points:
- exit_points.remove(None)
-
- exit_points |= finally_exit_points
-
- else:
- exit_points = set([None])
-
- return exit_points
-
-def _loop_has_unreachable_condition(node):
- for exit_point in _get_exit_points(node):
- if exit_point is None:
- return False
- if exit_point.kind == tok.CONTINUE:
- return False
- return True
-
-@lookfor((tok.EQOP, op.EQ))
-def comparison_type_conv(node):
- for kid in node.kids:
- if kid.kind == tok.PRIMARY and kid.opcode in (op.NULL, op.TRUE, op.FALSE):
- raise LintWarning(kid)
- if kid.kind == tok.NUMBER and not kid.dval:
- raise LintWarning(kid)
- if kid.kind == tok.STRING and not kid.atom:
- raise LintWarning(kid)
-
-@lookfor(tok.DEFAULT)
-def default_not_at_end(node):
- siblings = node.parent.kids
- if node.node_index != len(siblings)-1:
- raise LintWarning(siblings[node.node_index+1])
-
-@lookfor(tok.CASE)
-def duplicate_case_in_switch(node):
- # Only look at previous siblings
- siblings = node.parent.kids
- siblings = siblings[:node.node_index]
- # Compare values (first kid)
- node_value = node.kids[0]
- for sibling in siblings:
- if sibling.kind == tok.CASE:
- sibling_value = sibling.kids[0]
- if node_value.is_equivalent(sibling_value, True):
- raise LintWarning(node)
-
-@lookfor(tok.SWITCH)
-def missing_default_case(node):
- value, cases = node.kids
- for case in cases.kids:
- if case.kind == tok.DEFAULT:
- return
- raise LintWarning(node)
-
-@lookfor(tok.WITH)
-def with_statement(node):
- raise LintWarning(node)
-
-@lookfor(tok.EQOP, tok.RELOP)
-def useless_comparison(node):
- for lvalue, rvalue in itertools.combinations(node.kids, 2):
- if lvalue.is_equivalent(rvalue):
- raise LintWarning(node)
-
-@lookfor((tok.COLON, op.NAME))
-def use_of_label(node):
- raise LintWarning(node)
-
-@lookfor((tok.OBJECT, op.REGEXP))
-def misplaced_regex(node):
- if node.parent.kind == tok.NAME and node.parent.opcode == op.SETNAME:
- return # Allow in var statements
- if node.parent.kind == tok.ASSIGN and node.parent.opcode == op.NOP:
- return # Allow in assigns
- if node.parent.kind == tok.COLON and node.parent.parent.kind == tok.RC:
- return # Allow in object literals
- if node.parent.kind == tok.LP and node.parent.opcode == op.CALL:
- return # Allow in parameters
- if node.parent.kind == tok.DOT and node.parent.opcode == op.GETPROP:
- return # Allow in /re/.property
- if node.parent.kind == tok.RETURN:
- return # Allow for return values
- raise LintWarning(node)
-
-@lookfor(tok.ASSIGN)
-def assign_to_function_call(node):
- kid = node.kids[0]
- # Unpack parens.
- while kid.kind == tok.RP:
- kid, = kid.kids
- if kid.kind == tok.LP:
- raise LintWarning(node)
-
-@lookfor((tok.ASSIGN, None))
-def equal_as_assign(node):
- # Allow in VAR statements.
- if node.parent.parent and node.parent.parent.kind == tok.VAR:
- return
-
- if not node.parent.kind in (tok.SEMI, tok.RESERVED, tok.RP, tok.COMMA,
- tok.ASSIGN):
- raise LintWarning(node)
-
-@lookfor(tok.IF)
-def ambiguous_else_stmt(node):
- # Only examine this node if it has an else statement.
- condition, if_, else_ = node.kids
- if not else_:
- return
-
- tmp = node
- while tmp:
- # Curly braces always clarify if statements.
- if tmp.kind == tok.LC:
- return
- # Else is only ambiguous in the first branch of an if statement.
- if tmp.parent.kind == tok.IF and tmp.node_index == 1:
- raise LintWarning(else_)
- tmp = tmp.parent
-
-@lookfor(tok.IF, tok.WHILE, tok.DO, tok.FOR, tok.WITH)
-def block_without_braces(node):
- if node.kids[1].kind != tok.LC:
- raise LintWarning(node.kids[1])
-
-_block_nodes = (tok.IF, tok.WHILE, tok.DO, tok.FOR, tok.WITH)
-@lookfor(*_block_nodes)
-def ambiguous_nested_stmt(node):
- # Ignore "else if"
- if node.kind == tok.IF and node.node_index == 2 and node.parent.kind == tok.IF:
- return
-
- # If the parent is a block, it means a block statement
- # was inside a block statement without clarifying curlies.
- # (Otherwise, the node type would be tok.LC.)
- if node.parent.kind in _block_nodes:
- raise LintWarning(node)
-
-@lookfor(tok.INC, tok.DEC)
-def inc_dec_within_stmt(node):
- if node.parent.kind == tok.SEMI:
- return
-
- # Allow within the third part of the "for"
- tmp = node
- while tmp and tmp.parent and tmp.parent.kind == tok.COMMA:
- tmp = tmp.parent
- if tmp and tmp.node_index == 2 and \
- tmp.parent.kind == tok.RESERVED and \
- tmp.parent.parent.kind == tok.FOR:
- return
-
- raise LintWarning(node)
-
-@lookfor(tok.COMMA)
-def comma_separated_stmts(node):
- # Allow within the first and third part of "for(;;)"
- if _get_branch_in_for(node) in (0, 2):
- return
- # This is an array
- if node.parent.kind == tok.RB:
- return
- raise LintWarning(node)
-
-@lookfor(tok.SEMI)
-def empty_statement(node):
- if not node.kids[0]:
- raise LintWarning(node)
-@lookfor(tok.LC)
-def empty_statement_(node):
- if node.kids:
- return
- # Ignore the outermost block.
- if not node.parent:
- return
- # Some empty blocks are meaningful.
- if node.parent.kind in (tok.CATCH, tok.CASE, tok.DEFAULT, tok.SWITCH, tok.FUNCTION):
- return
- raise LintWarning(node)
-
-@lookfor(tok.CASE, tok.DEFAULT)
-def missing_break(node):
- # The last item is handled separately
- if node.node_index == len(node.parent.kids)-1:
- return
- case_contents = node.kids[1]
- assert case_contents.kind == tok.LC
- # Ignore empty case statements
- if not case_contents.kids:
- return
- if None in _get_exit_points(case_contents):
- # Show the warning on the *next* node.
- raise LintWarning(node.parent.kids[node.node_index+1])
-
-@lookfor(tok.CASE, tok.DEFAULT)
-def missing_break_for_last_case(node):
- if node.node_index < len(node.parent.kids)-1:
- return
- case_contents = node.kids[1]
- assert case_contents.kind == tok.LC
- if None in _get_exit_points(case_contents):
- raise LintWarning(node)
-
-@lookfor(tok.INC)
-def multiple_plus_minus(node):
- if node.node_index == 0 and node.parent.kind == tok.PLUS:
- raise LintWarning(node)
-@lookfor(tok.DEC)
-def multiple_plus_minus_(node):
- if node.node_index == 0 and node.parent.kind == tok.MINUS:
- raise LintWarning(node)
-
-@lookfor((tok.NAME, op.SETNAME))
-def useless_assign(node):
- if node.parent.kind == tok.ASSIGN:
- assert node.node_index == 0
- value = node.parent.kids[1]
- elif node.parent.kind == tok.VAR:
- value = node.kids[0]
- if value and value.kind == tok.NAME and node.atom == value.atom:
- raise LintWarning(node)
-
-@lookfor(tok.BREAK, tok.CONTINUE, tok.RETURN, tok.THROW)
-def unreachable_code(node):
- if node.parent.kind == tok.LC:
- for sibling in node.parent.kids[node.node_index+1:]:
- if sibling.kind == tok.VAR:
- # Look for a variable assignment
- for variable in sibling.kids:
- value, = variable.kids
- if value:
- raise LintWarning(value)
- elif sibling.kind == tok.FUNCTION:
- # Functions are always declared.
- pass
- else:
- raise LintWarning(sibling)
-
-@lookfor(tok.FOR)
-def unreachable_code_(node):
- # Warn if the for loop always exits.
- preamble, code = node.kids
- if preamble.kind == tok.RESERVED:
- pre, condition, post = preamble.kids
- if post:
- if _loop_has_unreachable_condition(code):
- raise LintWarning(post)
-
-@lookfor(tok.DO)
-def unreachable_code__(node):
- # Warn if the do..while loop always exits.
- code, condition = node.kids
- if _loop_has_unreachable_condition(code):
- raise LintWarning(condition)
-
-#TODO: @lookfor(tok.IF)
-def meaningless_block(node):
- condition, if_, else_ = node.kids
- if condition.kind == tok.PRIMARY and condition.opcode in (op.TRUE, op.FALSE, op.NULL):
- raise LintWarning(condition)
-#TODO: @lookfor(tok.WHILE)
-def meaningless_blocK_(node):
- condition = node.kids[0]
- if condition.kind == tok.PRIMARY and condition.opcode in (op.FALSE, op.NULL):
- raise LintWarning(condition)
-@lookfor(tok.LC)
-def meaningless_block__(node):
- if node.parent and node.parent.kind == tok.LC:
- raise LintWarning(node)
-
-@lookfor((tok.UNARYOP, op.VOID))
-def useless_void(node):
- raise LintWarning(node)
-
-@lookfor((tok.LP, op.CALL))
-def parseint_missing_radix(node):
- if node.kids[0].kind == tok.NAME and node.kids[0].atom == 'parseInt' and len(node.kids) <= 2:
- raise LintWarning(node)
-
-@lookfor(tok.NUMBER)
-def leading_decimal_point(node):
- if node.atom.startswith('.'):
- raise LintWarning(node)
-
-@lookfor(tok.NUMBER)
-def trailing_decimal_point(node):
- if node.parent.kind == tok.DOT:
- raise LintWarning(node)
- if node.atom.endswith('.'):
- raise LintWarning(node)
-
-_octal_regexp = re.compile('^0[0-9]')
-@lookfor(tok.NUMBER)
-def octal_number(node):
- if _octal_regexp.match(node.atom):
- raise LintWarning(node)
-
-@lookfor(tok.RC)
-def trailing_comma(node):
- if node.end_comma:
- # Warn on the last value in the dictionary.
- last_item = node.kids[-1]
- assert last_item.kind == tok.COLON
- key, value = last_item.kids
- raise LintWarning(value)
-
-@lookfor(tok.RB)
-def trailing_comma_in_array(node):
- if node.end_comma:
- # Warn on the last value in the array.
- raise LintWarning(node.kids[-1])
-
-@lookfor(tok.STRING)
-def useless_quotes(node):
- if node.node_index == 0 and node.parent.kind == tok.COLON:
- # Only warn if the quotes could safely be removed.
- if util.isidentifier(node.atom):
- raise LintWarning(node)
-
-@lookfor(tok.SEMI)
-def want_assign_or_call(node):
- child, = node.kids
- # Ignore empty statements.
- if not child:
- return
- # NOTE: Don't handle comma-separated statements.
- if child.kind in (tok.ASSIGN, tok.INC, tok.DEC, tok.DELETE, tok.COMMA):
- return
- if child.kind == tok.YIELD:
- return
- # Ignore function calls.
- if child.kind == tok.LP and child.opcode == op.CALL:
- return
- # Allow new function() { } as statements.
- if child.kind == tok.NEW:
- # The first kid is the constructor, followed by its arguments.
- grandchild = child.kids[0]
- if grandchild.kind == tok.FUNCTION:
- return
- raise LintWarning(child)
-
-def _check_return_value(node):
- name = node.fn_name or '(anonymous function)'
-
- def is_return_with_val(node):
- return node and node.kind == tok.RETURN and node.kids[0]
- def is_return_without_val(node):
- return node and node.kind == tok.RETURN and not node.kids[0]
-
- node, = node.kids
- assert node.kind == tok.LC
-
- exit_points = _get_exit_points(node)
- if filter(is_return_with_val, exit_points):
- # If the function returns a value, find all returns without a value.
- returns = filter(is_return_without_val, exit_points)
- returns.sort(key=lambda node: node.start_offset)
- if returns:
- raise LintWarning(returns[0], name=name)
- # Warn if the function sometimes exits naturally.
- if None in exit_points:
- raise LintWarning(node, name=name)
-
-@lookfor(tok.FUNCTION)
-def no_return_value(node):
- if node.fn_name:
- _check_return_value(node)
-
-@lookfor(tok.FUNCTION)
-def anon_no_return_value(node):
- if not node.fn_name:
- _check_return_value(node)
-
-@lookfor((tok.FOR, op.FORIN))
-def for_in_missing_identifier(node):
- assert node.kids[0].kind == tok.IN
- left, right = node.kids[0].kids
- if not left.kind in (tok.VAR, tok.NAME):
- raise LintWarning(left)
-
-@lookfor(tok.FUNCTION)
-def misplaced_function(node):
- # Ignore function statements.
- if node.opcode in (None, op.CLOSURE):
- return
-
- # Ignore parens.
- parent = node.parent
- while parent.kind == tok.RP:
- parent = parent.parent
-
- # Allow x = x || ...
- if parent.kind == tok.OR and len(parent.kids) == 2 and \
- node is parent.kids[-1]:
- parent = parent.parent
-
- if parent.kind == tok.NAME and parent.opcode == op.SETNAME:
- return # Allow in var statements
- if parent.kind == tok.ASSIGN and parent.opcode == op.NOP:
- return # Allow in assigns
- if parent.kind == tok.COLON and parent.parent.kind == tok.RC:
- return # Allow in object literals
- if parent.kind == tok.LP and parent.opcode in (op.CALL, op.SETCALL):
- return # Allow in parameters
- if parent.kind == tok.RETURN:
- return # Allow for return values
- if parent.kind == tok.NEW:
- return # Allow as constructors
- raise LintWarning(node)
-
-def _get_function_property_name(node):
- # Ignore function statements.
- if node.opcode in (None, op.CLOSURE):
- return
-
- # Ignore parens.
- parent = node.parent
- while parent.kind == tok.RP:
- parent = parent.parent
-
- # Allow x = x || ...
- if parent.kind == tok.OR and len(parent.kids) == 2 and \
- node is parent.kids[-1]:
- parent = parent.parent
-
- # Var assignment.
- if parent.kind == tok.NAME and parent.opcode == op.SETNAME:
- return parent.atom
-
- # Assignment.
- if parent.kind == tok.ASSIGN and parent.opcode == op.NOP:
- if parent.kids[0].kind == tok.NAME and \
- parent.kids[0].opcode == op.SETNAME:
- return parent.kids[0].atom
- if parent.kids[0].kind == tok.DOT and \
- parent.kids[0].opcode == op.SETPROP:
- return parent.kids[0].atom
- return '<error>'
-
- # Object literal.
- if parent.kind == tok.COLON and parent.parent.kind == tok.RC:
- return parent.kids[0].atom
-
-def _get_expected_function_name(node, decorate):
- name = _get_function_property_name(node)
- if name and decorate:
- return '__%s' % name
- return name
-
-@lookfor_class(tok.FUNCTION)
-class FunctionNameMissing(object):
- def __init__(self, conf):
- self._decorate = conf['decorate_function_name_warning']
-
- def __call__(self, node):
- if node.fn_name:
- return
-
- expected_name = _get_expected_function_name(node, self._decorate)
- if not expected_name is None:
- raise LintWarning(node, name=expected_name)
-
-@lookfor_class(tok.FUNCTION)
-class FunctionNameMismatch(object):
- def __init__(self, conf):
- self._decorate = conf['decorate_function_name_warning']
-
- def __call__(self, node):
- if not node.fn_name:
- return
-
- expected_name = _get_expected_function_name(node, self._decorate)
- if expected_name is None:
- return
-
- if expected_name != node.fn_name:
- raise LintWarning(node, fn_name=node.fn_name,
- prop_name=expected_name)
-
-@lookfor()
-def mismatch_ctrl_comments(node):
- pass
-
-@lookfor()
-def redeclared_var(node):
- pass
-
-@lookfor()
-def undeclared_identifier(node):
- pass
-
-@lookfor()
-def jsl_cc_not_understood(node):
- pass
-
-@lookfor()
-def nested_comment(node):
- pass
-
-@lookfor()
-def legacy_cc_not_understood(node):
- pass
-
-@lookfor()
-def var_hides_arg(node):
- pass
-
-@lookfor()
-def duplicate_formal(node):
- pass
-
-@lookfor(*_ALL_TOKENS)
-def missing_semicolon(node):
- if node.no_semi:
- if not _get_assigned_lambda(node):
- raise LintWarning(node)
-
-@lookfor(*_ALL_TOKENS)
-def missing_semicolon_for_lambda(node):
- if node.no_semi:
- # spidermonkey sometimes returns incorrect positions for var
- # statements, so use the position of the lambda instead.
- lambd...
[truncated message content] |
|
From: <mat...@us...> - 2014-10-27 22:25:37
|
Revision: 354
http://sourceforge.net/p/javascriptlint/code/354
Author: matthiasmiller
Date: 2014-10-27 22:25:27 +0000 (Mon, 27 Oct 2014)
Log Message:
-----------
Allow nesting config files.
Modified Paths:
--------------
trunk/javascriptlint/conf.py
Modified: trunk/javascriptlint/conf.py
===================================================================
--- trunk/javascriptlint/conf.py 2014-10-27 22:23:26 UTC (rev 353)
+++ trunk/javascriptlint/conf.py 2014-10-27 22:25:27 UTC (rev 354)
@@ -176,6 +176,16 @@
if not self.value:
raise ConfError('Invalid JavaScript version: %s' % parm)
+class ConfSetting(Setting):
+ wants_parm = True
+ wants_dir = True
+ def __init__(self, conf):
+ self._conf = conf
+ def load(self, enabled, parm, dir):
+ if dir:
+ parm = os.path.join(dir, parm)
+ self._conf.loadfile(parm)
+
class Conf:
def __init__(self):
recurse = BooleanSetting(False)
@@ -190,6 +200,7 @@
'context': BooleanSetting(True),
'process': ProcessSetting(recurse),
'default-version': JSVersionSetting(),
+ 'conf': ConfSetting(self),
# SpiderMonkey warnings
'no_return_value': BooleanSetting(True),
'equal_as_assign': BooleanSetting(True),
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2014-10-27 22:23:33
|
Revision: 353
http://sourceforge.net/p/javascriptlint/code/353
Author: matthiasmiller
Date: 2014-10-27 22:23:26 +0000 (Mon, 27 Oct 2014)
Log Message:
-----------
Format configuration errors correctly.
Modified Paths:
--------------
trunk/javascriptlint/conf.py
trunk/javascriptlint/jsl.py
Modified: trunk/javascriptlint/conf.py
===================================================================
--- trunk/javascriptlint/conf.py 2014-10-27 19:42:54 UTC (rev 352)
+++ trunk/javascriptlint/conf.py 2014-10-27 22:23:26 UTC (rev 353)
@@ -244,7 +244,10 @@
parm = line[len(name):].lstrip()
# Load the setting
- setting = self._settings[name]
+ try:
+ setting = self._settings[name]
+ except KeyError:
+ raise ConfError('Unrecognized setting: %s' % name)
args = {
'enabled': enabled
}
Modified: trunk/javascriptlint/jsl.py
===================================================================
--- trunk/javascriptlint/jsl.py 2014-10-27 19:42:54 UTC (rev 352)
+++ trunk/javascriptlint/jsl.py 2014-10-27 22:23:26 UTC (rev 353)
@@ -2,6 +2,7 @@
# vim: ts=4 sw=4 expandtab
import codecs
import fnmatch
+import functools
import glob
import os
import sys
@@ -27,12 +28,14 @@
script = fs.readfile(path, encoding)
jsparse.dump_tree(script)
+def _lint_warning(conf_, path, line, col, errname, errdesc):
+ _lint_results['warnings'] = _lint_results['warnings'] + 1
+ print util.format_error(conf_['output-format'], path, line, col,
+ errname, errdesc)
+
def _lint(paths, conf_, printpaths, encoding):
- def lint_error(path, line, col, errname, errdesc):
- _lint_results['warnings'] = _lint_results['warnings'] + 1
- print util.format_error(conf_['output-format'], path, line, col,
- errname, errdesc)
- lint.lint_files(paths, lint_error, encoding, conf=conf_, printpaths=printpaths)
+ lint.lint_files(paths, functools.partial(_lint_warning, conf_), encoding,
+ conf=conf_, printpaths=printpaths)
def _resolve_paths(path, recurse):
# Build a list of directories
@@ -116,7 +119,11 @@
conf_ = conf.Conf()
if options.conf:
- conf_.loadfile(options.conf)
+ try:
+ conf_.loadfile(options.conf)
+ except conf.ConfError, error:
+ _lint_warning(conf_, error.path, error.lineno, 0, 'conf_error',
+ unicode(error))
profile_func = _profile_disabled
if options.profile:
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2014-10-27 19:43:07
|
Revision: 352
http://sourceforge.net/p/javascriptlint/code/352
Author: matthiasmiller
Date: 2014-10-27 19:42:54 +0000 (Mon, 27 Oct 2014)
Log Message:
-----------
Add trailing_whitespace warning.
Modified Paths:
--------------
trunk/javascriptlint/conf.py
trunk/javascriptlint/jsparse.py
trunk/javascriptlint/lint.py
trunk/javascriptlint/warnings.py
trunk/jsengine/parser/_constants_kind.py
Modified: trunk/javascriptlint/conf.py
===================================================================
--- trunk/javascriptlint/conf.py 2014-10-27 19:11:53 UTC (rev 351)
+++ trunk/javascriptlint/conf.py 2014-10-27 19:42:54 UTC (rev 352)
@@ -11,6 +11,7 @@
'block_without_braces',
'function_name_missing',
'function_name_mismatch',
+ 'trailing_whitespace',
)
def _getwarningsconf():
Modified: trunk/javascriptlint/jsparse.py
===================================================================
--- trunk/javascriptlint/jsparse.py 2014-10-27 19:11:53 UTC (rev 351)
+++ trunk/javascriptlint/jsparse.py 2014-10-27 19:42:54 UTC (rev 352)
@@ -87,6 +87,20 @@
possible_comments = findpossiblecomments(script, start_offset)
return filtercomments(possible_comments, root_node)
+def find_trailing_whitespace(script, script_offset):
+ nodes = []
+
+ trailing_whitespace = re.compile(r'\S(?P<whitespace>[^\S\r\n]+)([\r\n]|$)')
+
+ for match in trailing_whitespace.finditer(script):
+ start = match.start('whitespace')
+ end = match.end('whitespace')
+ nodes.append(ParseNode(kind.WHITESPACE, None,
+ script_offset + start,
+ script_offset + end-1,
+ script[start:end], []))
+ return nodes
+
def is_compilable_unit(script, jsversion):
jsversion = jsversion or JSVersion.default()
assert isvalidversion(jsversion)
@@ -262,7 +276,22 @@
testcomment('%s' % comment, 7, 7)
testcomment(' %s' % comment, 7, 8)
testcomment('\n\n %s' % comment, 7, 10)
+ def testTrailingWhitespace(self):
+ def testwhitespace(text, expected_whitespace):
+ nodes = find_trailing_whitespace(text, 0)
+ if expected_whitespace:
+ node, = nodes
+ self.assertEquals(node.atom, expected_whitespace)
+ else:
+ self.assertEquals(nodes, [])
+ testwhitespace(' ', '')
+ testwhitespace(' \n', '')
+ testwhitespace('a \n', ' ')
+ testwhitespace('a\n ', '')
+ testwhitespace('a\n {} ', ' ')
+ testwhitespace('a\n {} \n', ' ')
+
if __name__ == '__main__':
unittest.main()
Modified: trunk/javascriptlint/lint.py
===================================================================
--- trunk/javascriptlint/lint.py 2014-10-27 19:11:53 UTC (rev 351)
+++ trunk/javascriptlint/lint.py 2014-10-27 19:42:54 UTC (rev 352)
@@ -511,6 +511,9 @@
unused_scope = script_cache.scope.find_scope(node)
unused_scope.set_unused(name, node)
+ for node in jsparse.find_trailing_whitespace(script, script_offset):
+ report(node, 'trailing_whitespace')
+
def _lint_script_parts(script_parts, script_cache, lint_error, conf, import_callback):
def report_lint(node, errname, offset=0, **errargs):
errdesc = warnings.format_error(errname, **errargs)
Modified: trunk/javascriptlint/warnings.py
===================================================================
--- trunk/javascriptlint/warnings.py 2014-10-27 19:11:53 UTC (rev 351)
+++ trunk/javascriptlint/warnings.py 2014-10-27 19:42:54 UTC (rev 352)
@@ -105,6 +105,7 @@
'misplaced_function': 'unconventional use of function expression',
'function_name_missing': 'anonymous function should be named to match property name {name}',
'function_name_mismatch': 'function name {fn_name} does not match property name {prop_name}',
+ 'trailing_whitespace': 'trailing whitespace',
}
errors = {
Modified: trunk/jsengine/parser/_constants_kind.py
===================================================================
--- trunk/jsengine/parser/_constants_kind.py 2014-10-27 19:11:53 UTC (rev 351)
+++ trunk/jsengine/parser/_constants_kind.py 2014-10-27 19:42:54 UTC (rev 352)
@@ -64,6 +64,7 @@
'RB',
'STRING',
'YIELD', # TODO
+ 'WHITESPACE',
]
class _Kind(object):
def __init__(self, name):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2014-10-27 19:12:00
|
Revision: 351
http://sourceforge.net/p/javascriptlint/code/351
Author: matthiasmiller
Date: 2014-10-27 19:11:53 +0000 (Mon, 27 Oct 2014)
Log Message:
-----------
Fix incorrect warning about unreachable loop condition.
Modified Paths:
--------------
trunk/javascriptlint/warnings.py
Added Paths:
-----------
trunk/tests/bugs/unreachable_loop_condition.js
Modified: trunk/javascriptlint/warnings.py
===================================================================
--- trunk/javascriptlint/warnings.py 2014-02-10 23:48:14 UTC (rev 350)
+++ trunk/javascriptlint/warnings.py 2014-10-27 19:11:53 UTC (rev 351)
@@ -265,6 +265,14 @@
return exit_points
+def _loop_has_unreachable_condition(node):
+ for exit_point in _get_exit_points(node):
+ if exit_point is None:
+ return False
+ if exit_point.kind == tok.CONTINUE:
+ return False
+ return True
+
@lookfor((tok.EQOP, op.EQ))
def comparison_type_conv(node):
for kid in node.kids:
@@ -493,14 +501,14 @@
if preamble.kind == tok.RESERVED:
pre, condition, post = preamble.kids
if post:
- if not None in _get_exit_points(code):
+ if _loop_has_unreachable_condition(code):
raise LintWarning(post)
@lookfor(tok.DO)
def unreachable_code__(node):
# Warn if the do..while loop always exits.
code, condition = node.kids
- if not None in _get_exit_points(code):
+ if _loop_has_unreachable_condition(code):
raise LintWarning(condition)
#TODO: @lookfor(tok.IF)
Added: trunk/tests/bugs/unreachable_loop_condition.js
===================================================================
--- trunk/tests/bugs/unreachable_loop_condition.js (rev 0)
+++ trunk/tests/bugs/unreachable_loop_condition.js 2014-10-27 19:11:53 UTC (rev 351)
@@ -0,0 +1,36 @@
+function unreachable_loop_condition(skip) {
+ /* continue will run the condition.
+ */
+ for (var i = 0; i < 10; i++) {
+ if (skip)
+ continue;
+ break;
+ }
+
+ for (i = 0; i < 10; i++) { /*warning:unreachable_code*/
+ if (skip)
+ return;
+ break;
+ }
+
+
+ /* test with do..while
+ */
+ i = 0;
+ do {
+ i += 1;
+ if (skip)
+ continue;
+ break;
+ } while(i < 10);
+
+ i = 0;
+ do {
+ i += 1;
+ if (skip)
+ return;
+ break;
+ } while(i < 10); /*warning:unreachable_code*/
+
+}
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2014-02-10 23:48:17
|
Revision: 350
http://sourceforge.net/p/javascriptlint/code/350
Author: matthiasmiller
Date: 2014-02-10 23:48:14 +0000 (Mon, 10 Feb 2014)
Log Message:
-----------
Fix traceback on expected_tok error.
Modified Paths:
--------------
trunk/javascriptlint/warnings.py
trunk/jsengine/tokenizer/__init__.py
Added Paths:
-----------
trunk/tests/errors/expected_tok.js
Modified: trunk/javascriptlint/warnings.py
===================================================================
--- trunk/javascriptlint/warnings.py 2014-02-10 15:09:21 UTC (rev 349)
+++ trunk/javascriptlint/warnings.py 2014-02-10 23:48:14 UTC (rev 350)
@@ -124,9 +124,10 @@
errdesc = warnings[errname]
try:
- errdesc = re.sub(r"{(\w+)}", lambda match: errargs[match.group(1)], errdesc)
+ keyword = re.compile(r"{(\w+)}")
+ errdesc = keyword.sub(lambda match: errargs[match.group(1)], errdesc)
except (TypeError, KeyError):
- raise KeyError('Invalid keyword in error: ' + errdesc)
+ raise KeyError('Invalid keyword in error %s: %s' % (errname, errdesc))
return errdesc
_visitors = []
Modified: trunk/jsengine/tokenizer/__init__.py
===================================================================
--- trunk/jsengine/tokenizer/__init__.py 2014-02-10 15:09:21 UTC (rev 349)
+++ trunk/jsengine/tokenizer/__init__.py 2014-02-10 23:48:14 UTC (rev 350)
@@ -170,7 +170,7 @@
encountered = self.advance()
if encountered.tok != tok:
raise JSSyntaxError(encountered.start_offset, 'expected_tok',
- { 'token': tok })
+ { 'token': tok.getliteral() })
return encountered
def expect_identifiername(self):
Added: trunk/tests/errors/expected_tok.js
===================================================================
--- trunk/tests/errors/expected_tok.js (rev 0)
+++ trunk/tests/errors/expected_tok.js 2014-02-10 23:48:14 UTC (rev 350)
@@ -0,0 +1,4 @@
+function expected_tok() {
+ return { a, }; /*warning:expected_tok*/
+}
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2014-02-10 15:09:25
|
Revision: 349
http://sourceforge.net/p/javascriptlint/code/349
Author: matthiasmiller
Date: 2014-02-10 15:09:21 +0000 (Mon, 10 Feb 2014)
Log Message:
-----------
Fix warning position for trailing commas.
Modified Paths:
--------------
trunk/javascriptlint/warnings.py
trunk/tests/warnings/spidermonkey/trailing_comma.js
trunk/tests/warnings/trailing_comma_in_array.js
Modified: trunk/javascriptlint/warnings.py
===================================================================
--- trunk/javascriptlint/warnings.py 2014-01-08 22:59:01 UTC (rev 348)
+++ trunk/javascriptlint/warnings.py 2014-02-10 15:09:21 UTC (rev 349)
@@ -547,12 +547,17 @@
@lookfor(tok.RC)
def trailing_comma(node):
if node.end_comma:
- raise LintWarning(node)
+ # Warn on the last value in the dictionary.
+ last_item = node.kids[-1]
+ assert last_item.kind == tok.COLON
+ key, value = last_item.kids
+ raise LintWarning(value)
@lookfor(tok.RB)
def trailing_comma_in_array(node):
if node.end_comma:
- raise LintWarning(node)
+ # Warn on the last value in the array.
+ raise LintWarning(node.kids[-1])
@lookfor(tok.STRING)
def useless_quotes(node):
Modified: trunk/tests/warnings/spidermonkey/trailing_comma.js
===================================================================
--- trunk/tests/warnings/spidermonkey/trailing_comma.js 2014-01-08 22:59:01 UTC (rev 348)
+++ trunk/tests/warnings/spidermonkey/trailing_comma.js 2014-02-10 15:09:21 UTC (rev 349)
@@ -1,5 +1,8 @@
/*jsl:option explicit*/
function trailing_comma() {
/* illegal - trailing comma */
- return { name: 'value', }; /*warning:trailing_comma*/
+ return {
+ name:
+ 'value', /*warning:trailing_comma*/
+ };
}
Modified: trunk/tests/warnings/trailing_comma_in_array.js
===================================================================
--- trunk/tests/warnings/trailing_comma_in_array.js 2014-01-08 22:59:01 UTC (rev 348)
+++ trunk/tests/warnings/trailing_comma_in_array.js 2014-02-10 15:09:21 UTC (rev 349)
@@ -5,4 +5,12 @@
a = [1,,2];
a = [1,]; /*warning:trailing_comma_in_array*/
a = [1,,]; /*warning:trailing_comma_in_array*/
+ a = [
+ , /*warning:trailing_comma_in_array*/
+ ];
+ a = [
+ 1,
+ 2,
+ 3, /*warning:trailing_comma_in_array*/
+ ];
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2014-01-08 22:59:05
|
Revision: 348
http://sourceforge.net/p/javascriptlint/code/348
Author: matthiasmiller
Date: 2014-01-08 22:59:01 +0000 (Wed, 08 Jan 2014)
Log Message:
-----------
Allow the function_name warnings to require name decoration.
Modified Paths:
--------------
trunk/javascriptlint/conf.py
trunk/javascriptlint/lint.py
trunk/javascriptlint/warnings.py
trunk/tests/warnings/function_name_mismatch.js
trunk/tests/warnings/function_name_missing.js
Added Paths:
-----------
trunk/tests/warnings/function_name_mismatch_decorated.js
Modified: trunk/javascriptlint/conf.py
===================================================================
--- trunk/javascriptlint/conf.py 2013-12-07 16:32:54 UTC (rev 347)
+++ trunk/javascriptlint/conf.py 2014-01-08 22:59:01 UTC (rev 348)
@@ -94,6 +94,12 @@
#+default-type text/javascript;version=1.5
#+default-type text/javascript;e4x=1
+###
+# Some browsers pollute the namespace when using the "function_name_missing"
+# or "function_name_mismatch" warning. Enable this option to require a
+# double-underscore prefix.
+#+decorate_function_name_warning
+
### Files
# Specify which files to lint
# Use "+recurse" to enable recursion (disabled by default).
@@ -186,7 +192,8 @@
# SpiderMonkey warnings
'no_return_value': BooleanSetting(True),
'equal_as_assign': BooleanSetting(True),
- 'anon_no_return_value': BooleanSetting(True)
+ 'anon_no_return_value': BooleanSetting(True),
+ 'decorate_function_name_warning': BooleanSetting(False),
}
for name in warnings.warnings:
self._settings[name] = BooleanSetting(True)
Modified: trunk/javascriptlint/lint.py
===================================================================
--- trunk/javascriptlint/lint.py 2013-12-07 16:32:54 UTC (rev 347)
+++ trunk/javascriptlint/lint.py 2014-01-08 22:59:01 UTC (rev 348)
@@ -482,7 +482,7 @@
# Find all visitors and convert them into "onpush" callbacks that call "report"
visitors = {
- 'push': warnings.make_visitors()
+ 'push': warnings.make_visitors(conf)
}
for event in visitors:
for kind, callbacks in visitors[event].items():
Modified: trunk/javascriptlint/warnings.py
===================================================================
--- trunk/javascriptlint/warnings.py 2013-12-07 16:32:54 UTC (rev 347)
+++ trunk/javascriptlint/warnings.py 2014-01-08 22:59:01 UTC (rev 348)
@@ -139,6 +139,20 @@
_visitors.append((arg, fn))
return decorate
+_visitor_classes = []
+def lookfor_class(*args):
+ def decorate(cls):
+ # Convert the class name to camel case
+ camelcase = re.sub('([A-Z])', r'_\1', cls.__name__).lower().lstrip('_')
+
+ cls.warning = camelcase.rstrip('_')
+ assert cls.warning in warnings, \
+ 'Missing warning description: %s' % cls.warning
+
+ for arg in args:
+ _visitor_classes.append((arg, cls))
+ return decorate
+
class LintWarning(Exception):
def __init__(self, node, **errargs):
self.node = node
@@ -638,7 +652,7 @@
return # Allow as constructors
raise LintWarning(node)
-def _get_expected_function_name(node):
+def _get_function_property_name(node):
# Ignore function statements.
if node.opcode in (None, op.CLOSURE):
return
@@ -671,27 +685,42 @@
if parent.kind == tok.COLON and parent.parent.kind == tok.RC:
return parent.kids[0].atom
-@lookfor(tok.FUNCTION)
-def function_name_missing(node):
- if node.fn_name:
- return
+def _get_expected_function_name(node, decorate):
+ name = _get_function_property_name(node)
+ if name and decorate:
+ return '__%s' % name
+ return name
- expected_name = _get_expected_function_name(node)
- if not expected_name is None:
- raise LintWarning(node, name=expected_name)
+@lookfor_class(tok.FUNCTION)
+class FunctionNameMissing(object):
+ def __init__(self, conf):
+ self._decorate = conf['decorate_function_name_warning']
-@lookfor(tok.FUNCTION)
-def function_name_mismatch(node):
- if not node.fn_name:
- return
+ def __call__(self, node):
+ if node.fn_name:
+ return
- expected_name = _get_expected_function_name(node)
- if expected_name is None:
- return
+ expected_name = _get_expected_function_name(node, self._decorate)
+ if not expected_name is None:
+ raise LintWarning(node, name=expected_name)
- if expected_name != node.fn_name:
- raise LintWarning(node, fn_name=node.fn_name, prop_name=expected_name)
+@lookfor_class(tok.FUNCTION)
+class FunctionNameMismatch(object):
+ def __init__(self, conf):
+ self._decorate = conf['decorate_function_name_warning']
+ def __call__(self, node):
+ if not node.fn_name:
+ return
+
+ expected_name = _get_expected_function_name(node, self._decorate)
+ if expected_name is None:
+ return
+
+ if expected_name != node.fn_name:
+ raise LintWarning(node, fn_name=node.fn_name,
+ prop_name=expected_name)
+
@lookfor()
def mismatch_ctrl_comments(node):
pass
@@ -755,9 +784,13 @@
def dup_option_explicit(node):
pass
-def make_visitors():
+def make_visitors(conf):
+ all_visitors = list(_visitors)
+ for kind, klass in _visitor_classes:
+ all_visitors.append((kind, klass(conf=conf)))
+
visitors = {}
- for kind, func in _visitors:
+ for kind, func in all_visitors:
try:
visitors[kind].append(func)
except KeyError:
Modified: trunk/tests/warnings/function_name_mismatch.js
===================================================================
--- trunk/tests/warnings/function_name_mismatch.js 2013-12-07 16:32:54 UTC (rev 347)
+++ trunk/tests/warnings/function_name_mismatch.js 2014-01-08 22:59:01 UTC (rev 348)
@@ -34,6 +34,12 @@
}
function Class() {
+ this.getStr = function getSt() { /*warning:function_name_mismatch*/
+ return this.str;
+ };
+ this.setStr = function setStr(s) {
+ this.str = s;
+ };
}
Class.prototype.get = function gt() { /*warning:function_name_mismatch*/
return this.value;
Copied: trunk/tests/warnings/function_name_mismatch_decorated.js (from rev 347, trunk/tests/warnings/function_name_mismatch.js)
===================================================================
--- trunk/tests/warnings/function_name_mismatch_decorated.js (rev 0)
+++ trunk/tests/warnings/function_name_mismatch_decorated.js 2014-01-08 22:59:01 UTC (rev 348)
@@ -0,0 +1,32 @@
+/*conf:+function_name_mismatch*/
+/*conf:+decorate_function_name_warning*/
+function function_name_mismatch_decorated() {
+ var f = function bogus() { /*warning:function_name_mismatch*/
+ };
+ var g = function g() { /*warning:function_name_mismatch*/
+ };
+ var h = function __h() {
+ };
+
+ f = new function bogus() {
+ };
+ f = new function() {
+ };
+
+ f = (function() {
+ return 10;
+ })();
+
+ function Class() {
+ }
+ Class.prototype.get = function gt() { /*warning:function_name_mismatch*/
+ return this.value;
+ };
+ Class.prototype.set = function set(value) { /*warning:function_name_mismatch*/
+ this.value = value;
+ };
+ Class.prototype.inc = function __inc(value) {
+ this.value++;
+ };
+}
+
Modified: trunk/tests/warnings/function_name_missing.js
===================================================================
--- trunk/tests/warnings/function_name_missing.js 2013-12-07 16:32:54 UTC (rev 347)
+++ trunk/tests/warnings/function_name_missing.js 2014-01-08 22:59:01 UTC (rev 348)
@@ -28,6 +28,12 @@
}
function Class() {
+ this.getStr = function () { /*warning:function_name_missing*/
+ return this.str;
+ };
+ this.setStr = function setStr(s) {
+ this.str = s;
+ };
}
Class.prototype.get = function () { /*warning:function_name_missing*/
return this.value;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2013-12-07 16:32:57
|
Revision: 347
http://sourceforge.net/p/javascriptlint/code/347
Author: matthiasmiller
Date: 2013-12-07 16:32:54 +0000 (Sat, 07 Dec 2013)
Log Message:
-----------
#46 Function name mismatch warning when assigning to property
Apply attached patched.
Modified Paths:
--------------
trunk/javascriptlint/warnings.py
trunk/tests/warnings/function_name_mismatch.js
trunk/tests/warnings/function_name_missing.js
Modified: trunk/javascriptlint/warnings.py
===================================================================
--- trunk/javascriptlint/warnings.py 2013-10-10 15:28:32 UTC (rev 346)
+++ trunk/javascriptlint/warnings.py 2013-12-07 16:32:54 UTC (rev 347)
@@ -662,6 +662,9 @@
if parent.kids[0].kind == tok.NAME and \
parent.kids[0].opcode == op.SETNAME:
return parent.kids[0].atom
+ if parent.kids[0].kind == tok.DOT and \
+ parent.kids[0].opcode == op.SETPROP:
+ return parent.kids[0].atom
return '<error>'
# Object literal.
Modified: trunk/tests/warnings/function_name_mismatch.js
===================================================================
--- trunk/tests/warnings/function_name_mismatch.js 2013-10-10 15:28:32 UTC (rev 346)
+++ trunk/tests/warnings/function_name_mismatch.js 2013-12-07 16:32:54 UTC (rev 347)
@@ -32,5 +32,14 @@
function x() {
}
+
+ function Class() {
+ }
+ Class.prototype.get = function gt() { /*warning:function_name_mismatch*/
+ return this.value;
+ };
+ Class.prototype.set = function set(value) {
+ this.value = value;
+ };
}
Modified: trunk/tests/warnings/function_name_missing.js
===================================================================
--- trunk/tests/warnings/function_name_missing.js 2013-10-10 15:28:32 UTC (rev 346)
+++ trunk/tests/warnings/function_name_missing.js 2013-12-07 16:32:54 UTC (rev 347)
@@ -26,5 +26,14 @@
function x() {
}
+
+ function Class() {
+ }
+ Class.prototype.get = function () { /*warning:function_name_missing*/
+ return this.value;
+ };
+ Class.prototype.set = function set(value) {
+ this.value = value;
+ };
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2013-10-10 15:28:35
|
Revision: 346
http://sourceforge.net/p/javascriptlint/code/346
Author: matthiasmiller
Date: 2013-10-10 15:28:32 +0000 (Thu, 10 Oct 2013)
Log Message:
-----------
Refactor punctuator/keyword handling.
Modified Paths:
--------------
trunk/jsengine/tokenizer/__init__.py
trunk/jsengine/tokenizer/tok.py
Modified: trunk/jsengine/tokenizer/__init__.py
===================================================================
--- trunk/jsengine/tokenizer/__init__.py 2013-10-10 15:25:47 UTC (rev 345)
+++ trunk/jsengine/tokenizer/__init__.py 2013-10-10 15:28:32 UTC (rev 346)
@@ -5,15 +5,11 @@
_WHITESPACE = u'\u0020\t\u000B\u000C\u00A0\uFFFF'
_LINETERMINATOR = u'\u000A\u000D\u2028\u2029'
_DIGITS = u'0123456789'
-_DOT_DIGITS = [u'.%s' % digit for digit in _DIGITS]
_HEX_DIGITS = _DIGITS + u'abcdefABCDEF'
_IDENT = u'abcdefghijklmnopqrstuvwxyz' + \
u'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + \
u'$_'
-_KEYWORDS = tok.getkeywords()
-_PUNCTUATOR_TREE = tok.get_punctuator_tree()
-
class _Char(object):
def __init__(self, u):
assert isinstance(u, int) or u is None, u
@@ -179,7 +175,7 @@
def expect_identifiername(self):
encountered = self.advance()
- if encountered.tok in list(_KEYWORDS.values()):
+ if tok.keywords.has(encountered.tok) != -1:
encountered.tok = tok.NAME
if encountered.tok != tok.NAME:
raise JSSyntaxError(encountered.start_offset, 'syntax_error')
@@ -332,29 +328,28 @@
atom = stream.get_watched_reads()
return Token(tok.NUMBER, atom=atom)
- if c.uval in _PUNCTUATOR_TREE:
- d = _PUNCTUATOR_TREE[c.uval]
+ if tok.punctuators.hasprefix(c.tostr()):
+ s = c.tostr()
while True:
c = stream.peekchr()
- if c and c.uval in d:
+ if c and tok.punctuators.hasprefix(s + c.tostr()):
+ s += c.tostr()
stream.readchr()
- d = d[c.uval]
else:
break
- try:
- return Token(d[-1])
- except KeyError:
- print('oops')
+ d = tok.punctuators.get(s)
+ if not d:
raise JSSyntaxError(stream.get_offset(), 'syntax_error')
-
+ return Token(d)
if c.instr(_IDENT):
while stream.readchrin(_IDENT + _DIGITS):
pass
atom = stream.get_watched_reads()
- if atom in _KEYWORDS:
- return Token(_KEYWORDS[atom], atom=atom)
- return Token(tok.NAME, atom=atom)
+ tt = tok.keywords.get(atom, tok.NAME)
+ t = Token(tt)
+ t.atom = atom
+ return t
raise JSSyntaxError(stream.get_offset(), 'unexpected_char',
{ 'char': c.tostr() })
Modified: trunk/jsengine/tokenizer/tok.py
===================================================================
--- trunk/jsengine/tokenizer/tok.py 2013-10-10 15:25:47 UTC (rev 345)
+++ trunk/jsengine/tokenizer/tok.py 2013-10-10 15:28:32 UTC (rev 346)
@@ -10,12 +10,10 @@
def __repr__(self):
return 'TokenType(%r, %r)' % (self._category, self._literal)
- @property
- def category(self):
+ def getcategory(self):
return self._category
- @property
- def literal(self):
+ def getliteral(self):
return self._literal
# Symbols
@@ -113,16 +111,44 @@
SPACE = TokenType('other', '(sp)')
STRING = TokenType('other', '(str)')
-def getkeywords():
- return dict((t.literal, t) for t in _ALL_TOKENS if t.category == 'kw')
+# Freeze the list of keywords
+_ALL_TOKENS = tuple(_ALL_TOKENS)
-def get_punctuator_tree():
- tree = {}
- for punctuator in (t for t in _ALL_TOKENS if t.category == 'sym'):
- leaf = tree
- for c in punctuator.literal:
- leaf = leaf.setdefault(ord(c), {})
- assert not None in leaf, punctuator.literal
- leaf[-1] = punctuator
- return tree
+class _Keywords(object):
+ def __init__(self):
+ self._d = {}
+ for tt in _ALL_TOKENS:
+ if tt.getcategory() == 'kw':
+ self._d[tt.getliteral()] = tt
+ def get(self, literal, default):
+ return self._d.get(literal, default)
+
+ def has(self, tok):
+ for iter in self._d.values():
+ if iter == tok:
+ return True
+ return False
+
+keywords = _Keywords()
+
+class _Punctuators(object):
+ def __init__(self):
+ self._prefixes = {}
+ self._punctuators = {}
+
+ for t in _ALL_TOKENS:
+ if t.getcategory() == 'sym':
+ literal = t.getliteral()
+ for i in range(len(literal)):
+ prefix = literal[:i+1]
+ self._prefixes[prefix] = True
+ self._punctuators[literal] = t
+
+ def hasprefix(self, prefix):
+ return self._prefixes.get(prefix, False)
+
+ def get(self, literal):
+ return self._punctuators.get(literal)
+
+punctuators = _Punctuators()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2013-10-10 15:25:51
|
Revision: 345
http://sourceforge.net/p/javascriptlint/code/345
Author: matthiasmiller
Date: 2013-10-10 15:25:47 +0000 (Thu, 10 Oct 2013)
Log Message:
-----------
Fix variable name in next_withregexp.
Modified Paths:
--------------
trunk/jsengine/parser/__init__.py
trunk/jsengine/tokenizer/__init__.py
Modified: trunk/jsengine/parser/__init__.py
===================================================================
--- trunk/jsengine/parser/__init__.py 2013-10-10 15:24:17 UTC (rev 344)
+++ trunk/jsengine/parser/__init__.py 2013-10-10 15:25:47 UTC (rev 345)
@@ -850,6 +850,13 @@
self.assert_(is_compilable_unit('', 'default'))
self.assert_(is_compilable_unit('/**/', 'default'))
self.assert_(not is_compilable_unit('/*', 'default'))
+ def testRegExpLineBreak(self):
+ try:
+ parsestring('re = /[\n');
+ except JSSyntaxError as error:
+ self.assertEqual(error.offset, 5)
+ else:
+ self.assert_(False)
def testUnterminatedComment(self):
try:
parsestring('/*')
Modified: trunk/jsengine/tokenizer/__init__.py
===================================================================
--- trunk/jsengine/tokenizer/__init__.py 2013-10-10 15:24:17 UTC (rev 344)
+++ trunk/jsengine/tokenizer/__init__.py 2013-10-10 15:25:47 UTC (rev 345)
@@ -165,7 +165,7 @@
self._peeked = []
if token.tok == tok.ERROR:
self._error = True
- raise JSSyntaxError(peek.start_offset, peek.atom or 'syntax_error')
+ raise JSSyntaxError(token.start_offset, token.atom or 'syntax_error')
return token
else:
return self.advance()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2013-10-10 15:24:22
|
Revision: 344
http://sourceforge.net/p/javascriptlint/code/344
Author: matthiasmiller
Date: 2013-10-10 15:24:17 +0000 (Thu, 10 Oct 2013)
Log Message:
-----------
Run jsengine unit tests and fix broken tests.
Modified Paths:
--------------
trunk/javascriptlint/jsl.py
trunk/jsengine/parser/__init__.py
Modified: trunk/javascriptlint/jsl.py
===================================================================
--- trunk/javascriptlint/jsl.py 2013-10-10 14:07:41 UTC (rev 343)
+++ trunk/javascriptlint/jsl.py 2013-10-10 15:24:17 UTC (rev 344)
@@ -12,6 +12,7 @@
import fs
import htmlparse
import jsparse
+import jsengine.parser
import lint
import util
import version
@@ -123,7 +124,7 @@
if options.unittest:
suite = unittest.TestSuite();
- for module in [conf, htmlparse, jsparse, lint, util]:
+ for module in [conf, htmlparse, jsengine.parser, jsparse, lint, util]:
suite.addTest(unittest.findTestCases(module))
runner = unittest.TextTestRunner(verbosity=options.verbosity)
Modified: trunk/jsengine/parser/__init__.py
===================================================================
--- trunk/jsengine/parser/__init__.py 2013-10-10 14:07:41 UTC (rev 343)
+++ trunk/jsengine/parser/__init__.py 2013-10-10 15:24:17 UTC (rev 344)
@@ -854,7 +854,7 @@
try:
parsestring('/*')
except JSSyntaxError as error:
- self.assertEqual(error.pos, NodePos(0, 1))
+ self.assertEqual(error.offset, 1)
else:
self.assert_(False)
def testObjectEndComma(self):
@@ -867,9 +867,9 @@
self.assertEquals(left.atom, 'a')
self.assertEquals(right.kind, kind.RC)
node = right.end_comma
- self.assertEquals(node.kind, tok.COMMA)
- self.assertEquals(node.start_offset, NodePos(0, 6))
- self.assertEquals(node.end_offset, NodePos(0, 6))
+ self.assertEquals(node.kind, kind.COMMA)
+ self.assertEquals(node.start_offset, 6)
+ self.assertEquals(node.end_offset, 6)
def _testArrayEndComma(self, script, col):
root = parsestring(script)
node, = root.kids
@@ -884,9 +884,9 @@
if col is None:
self.assert_(node is None)
else:
- self.assertEquals(node.kind, tok.COMMA)
- self.assertEquals(node.start_offset, NodePos(0, col))
- self.assertEquals(node.end_offset, NodePos(0, col))
+ self.assertEquals(node.kind, kind.COMMA)
+ self.assertEquals(node.start_offset, col)
+ self.assertEquals(node.end_offset, col)
def testArrayEndComma(self):
self._testArrayEndComma('a=[,]', 3)
self._testArrayEndComma('a=[a,]', 4)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2013-10-10 14:07:44
|
Revision: 343
http://sourceforge.net/p/javascriptlint/code/343
Author: matthiasmiller
Date: 2013-10-10 14:07:41 +0000 (Thu, 10 Oct 2013)
Log Message:
-----------
Fully distinguish between chars and strings.
Modified Paths:
--------------
trunk/jsengine/tokenizer/__init__.py
trunk/jsengine/tokenizer/tok.py
Modified: trunk/jsengine/tokenizer/__init__.py
===================================================================
--- trunk/jsengine/tokenizer/__init__.py 2013-10-09 22:41:46 UTC (rev 342)
+++ trunk/jsengine/tokenizer/__init__.py 2013-10-10 14:07:41 UTC (rev 343)
@@ -14,14 +14,43 @@
_KEYWORDS = tok.getkeywords()
_PUNCTUATOR_TREE = tok.get_punctuator_tree()
-def _str_has_chr(s, c):
- assert len(c) <= 1
- return c in s
+class _Char(object):
+ def __init__(self, u):
+ assert isinstance(u, int) or u is None, u
+ self._u = u
-def _chr_to_str(c):
- assert len(c) <= 1
- return c
+ @classmethod
+ def fromstr(cls, s, i):
+ return _Char(ord(s[i]))
+ @classmethod
+ def ord(cls, s):
+ return _Char(ord(s))
+
+ @property
+ def uval(self):
+ return self._u
+
+ def tostr(self):
+ if self._u is None:
+ return unicode()
+ return unichr(self._u)
+
+ def instr(self, s):
+ if self._u is None:
+ return False
+ return s.find(unichr(self._u)) != -1
+
+ def __hash__(self):
+ return hash(self._u)
+
+ def __eq__(self, other):
+ assert isinstance(other, _Char), other
+ return self._u == other._u
+
+ def __nonzero__(self):
+ return not self._u is None
+
class Token:
def __init__(self, tok, atom=None):
self.tok = tok
@@ -69,7 +98,7 @@
if self.peekchr() == expect:
self._offset += 1
return expect
- return ''
+ return _Char(None)
def readchrin(self, seq):
s = self.peekchrin(seq)
@@ -79,14 +108,14 @@
def peekchr(self):
if self._offset < len(self._content):
- return self._content[self._offset]
- return ''
+ return _Char.fromstr(self._content, self._offset)
+ return _Char(None)
def peekchrin(self, seq):
c = self.peekchr()
- if c and _str_has_chr(seq, c):
+ if c and c.instr(seq):
return c
- return ''
+ return _Char(None)
def readtextif(self, text):
""" Returns the string if found. Otherwise returns None.
@@ -184,20 +213,20 @@
stream = self._stream
while True:
c = stream.readchr()
- if c == '\\':
+ if c == _Char.ord('\\'):
c = stream.readchr()
- if c == '\n':
+ if c == _Char.ord('\n'):
return Token(tok.ERROR)
- elif c == '[':
+ elif c == _Char.ord('['):
while True:
c = stream.readchr()
- if c == '\n':
+ if c == _Char.ord('\n'):
return Token(tok.ERROR)
- elif c == ']':
+ elif c == _Char.ord(']'):
break
- elif c == '\n':
+ elif c == _Char.ord('\n'):
return Token(tok.ERROR)
- elif c == '/':
+ elif c == _Char.ord('/'):
break
# TODO: Validate and save
@@ -219,8 +248,8 @@
c = stream.readchr()
# WHITESPACE
- if _str_has_chr(_WHITESPACE, c) or _str_has_chr(_LINETERMINATOR, c):
- linebreak = _str_has_chr(_LINETERMINATOR, c)
+ if c.instr(_WHITESPACE) or c.instr(_LINETERMINATOR):
+ linebreak = c.instr(_LINETERMINATOR)
while True:
if stream.readchrin(_LINETERMINATOR):
linebreak = True
@@ -234,49 +263,49 @@
return Token(tok.SPACE)
# COMMENTS
- if c == '/':
- if stream.peekchr() == '/':
+ if c == _Char.ord('/'):
+ if stream.peekchr() == _Char.ord('/'):
while not stream.eof() and not stream.peekchrin(_LINETERMINATOR):
stream.readchr()
return Token(tok.CPP_COMMENT)
- if stream.peekchr() == '*':
+ if stream.peekchr() == _Char.ord('*'):
linebreak = False
while True:
if stream.eof():
return Token(tok.ERROR, atom='unterminated_comment')
c = stream.readchr()
- if _str_has_chr(_LINETERMINATOR, c):
+ if c.instr(_LINETERMINATOR):
linebreak = True
- elif c == '*' and stream.readchrif('/'):
+ elif c == _Char.ord('*') and stream.readchrif(_Char.ord('/')):
return Token(tok.C_COMMENT)
return Token(tok.EOF)
- elif c == '<':
+ elif c == _Char.ord('<'):
if stream.readtextif('!--'):
while not stream.eof() and not stream.peekchrin(_LINETERMINATOR):
stream.readchr()
return Token(tok.HTML_COMMENT)
# STRING LITERALS
- if c == '"' or c == "'":
+ if c == _Char.ord('"') or c == _Char.ord("'"):
# TODO: Decode
s = ''
quote = c
while True:
c = stream.readchr()
- if c == '\\':
+ if c == _Char.ord('\\'):
c = stream.readchr()
elif c == quote:
return Token(tok.STRING, atom=s)
- s += _chr_to_str(c)
+ s += c.tostr()
# NUMBERS
- if _str_has_chr(_DIGITS, c) or (c == '.' and stream.peekchrin(_DIGITS)):
+ if c.instr(_DIGITS) or (c == _Char.ord('.') and stream.peekchrin(_DIGITS)):
s = c # TODO
- if c == '0' and stream.readchrin('xX'):
+ if c == _Char.ord('0') and stream.readchrin('xX'):
# Hex
while stream.readchrin(_HEX_DIGITS):
pass
- elif c == '0' and stream.readchrin(_DIGITS):
+ elif c == _Char.ord('0') and stream.readchrin(_DIGITS):
# Octal
while stream.readchrin(_DIGITS):
pass
@@ -285,7 +314,7 @@
if c != '.':
while stream.readchrin(_DIGITS):
pass
- stream.readchrif('.')
+ stream.readchrif(_Char.ord('.'))
while stream.readchrin(_DIGITS):
pass
@@ -303,21 +332,22 @@
atom = stream.get_watched_reads()
return Token(tok.NUMBER, atom=atom)
- if c in _PUNCTUATOR_TREE:
- d = _PUNCTUATOR_TREE[c]
+ if c.uval in _PUNCTUATOR_TREE:
+ d = _PUNCTUATOR_TREE[c.uval]
while True:
- c = stream.readchrin(u''.join(d.keys()))
- if c:
- d = d[c]
+ c = stream.peekchr()
+ if c and c.uval in d:
+ stream.readchr()
+ d = d[c.uval]
else:
break
try:
- return Token(d[''])
+ return Token(d[-1])
except KeyError:
print('oops')
raise JSSyntaxError(stream.get_offset(), 'syntax_error')
- if _str_has_chr(_IDENT, c):
+ if c.instr(_IDENT):
while stream.readchrin(_IDENT + _DIGITS):
pass
@@ -327,4 +357,4 @@
return Token(tok.NAME, atom=atom)
raise JSSyntaxError(stream.get_offset(), 'unexpected_char',
- { 'char': _chr_to_str(c) })
+ { 'char': c.tostr() })
Modified: trunk/jsengine/tokenizer/tok.py
===================================================================
--- trunk/jsengine/tokenizer/tok.py 2013-10-09 22:41:46 UTC (rev 342)
+++ trunk/jsengine/tokenizer/tok.py 2013-10-10 14:07:41 UTC (rev 343)
@@ -121,8 +121,8 @@
for punctuator in (t for t in _ALL_TOKENS if t.category == 'sym'):
leaf = tree
for c in punctuator.literal:
- leaf = leaf.setdefault(c, {})
+ leaf = leaf.setdefault(ord(c), {})
assert not None in leaf, punctuator.literal
- leaf[''] = punctuator
+ leaf[-1] = punctuator
return tree
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2013-10-09 22:41:50
|
Revision: 342
http://sourceforge.net/p/javascriptlint/code/342
Author: matthiasmiller
Date: 2013-10-09 22:41:46 +0000 (Wed, 09 Oct 2013)
Log Message:
-----------
Distinguish between characters and strings.
Modified Paths:
--------------
trunk/jsengine/tokenizer/__init__.py
trunk/jsengine/tokenizer/tok.py
Modified: trunk/jsengine/tokenizer/__init__.py
===================================================================
--- trunk/jsengine/tokenizer/__init__.py 2013-10-09 21:51:03 UTC (rev 341)
+++ trunk/jsengine/tokenizer/__init__.py 2013-10-09 22:41:46 UTC (rev 342)
@@ -14,6 +14,14 @@
_KEYWORDS = tok.getkeywords()
_PUNCTUATOR_TREE = tok.get_punctuator_tree()
+def _str_has_chr(s, c):
+ assert len(c) <= 1
+ return c in s
+
+def _chr_to_str(c):
+ assert len(c) <= 1
+ return c
+
class Token:
def __init__(self, tok, atom=None):
self.tok = tok
@@ -51,23 +59,35 @@
return self._offset >= len(self._content)
def readchr(self):
- if self._offset < len(self._content):
+ c = self.peekchr()
+ if not c:
+ raise JSSyntaxError(self.get_offset(), 'unexpected_eof')
+ self._offset += 1
+ return c
+
+ def readchrif(self, expect):
+ if self.peekchr() == expect:
self._offset += 1
- return self._content[self._offset - 1]
- raise JSSyntaxError(self.get_offset()-1, 'unexpected_eof')
+ return expect
+ return ''
- def readchrif(self, seq):
- s = self.peekchrif(seq)
+ def readchrin(self, seq):
+ s = self.peekchrin(seq)
if s:
- assert len(s) == 1
self._offset += 1
return s
- def peekchrif(self, seq):
- if self._offset < len(self._content) and \
- self._content[self._offset] in seq:
+ def peekchr(self):
+ if self._offset < len(self._content):
return self._content[self._offset]
+ return ''
+ def peekchrin(self, seq):
+ c = self.peekchr()
+ if c and _str_has_chr(seq, c):
+ return c
+ return ''
+
def readtextif(self, text):
""" Returns the string if found. Otherwise returns None.
"""
@@ -182,7 +202,7 @@
# TODO: Validate and save
while True:
- c = stream.readchrif(_IDENT)
+ c = stream.readchrin(_IDENT)
if not c:
break
@@ -194,15 +214,17 @@
if stream.eof():
return Token(tok.EOF)
+ stream.watch_reads()
+
c = stream.readchr()
# WHITESPACE
- if c in _WHITESPACE or c in _LINETERMINATOR:
- linebreak = c in _LINETERMINATOR
+ if _str_has_chr(_WHITESPACE, c) or _str_has_chr(_LINETERMINATOR, c):
+ linebreak = _str_has_chr(_LINETERMINATOR, c)
while True:
- if stream.readchrif(_LINETERMINATOR):
+ if stream.readchrin(_LINETERMINATOR):
linebreak = True
- elif stream.readchrif(_WHITESPACE):
+ elif stream.readchrin(_WHITESPACE):
pass
else:
break
@@ -213,24 +235,24 @@
# COMMENTS
if c == '/':
- if stream.peekchrif("/"):
- while not stream.eof() and not stream.peekchrif(_LINETERMINATOR):
+ if stream.peekchr() == '/':
+ while not stream.eof() and not stream.peekchrin(_LINETERMINATOR):
stream.readchr()
return Token(tok.CPP_COMMENT)
- if stream.peekchrif("*"):
+ if stream.peekchr() == '*':
linebreak = False
while True:
if stream.eof():
return Token(tok.ERROR, atom='unterminated_comment')
c = stream.readchr()
- if c in _LINETERMINATOR:
+ if _str_has_chr(_LINETERMINATOR, c):
linebreak = True
elif c == '*' and stream.readchrif('/'):
return Token(tok.C_COMMENT)
return Token(tok.EOF)
elif c == '<':
if stream.readtextif('!--'):
- while not stream.eof() and not stream.peekchrif(_LINETERMINATOR):
+ while not stream.eof() and not stream.peekchrin(_LINETERMINATOR):
stream.readchr()
return Token(tok.HTML_COMMENT)
@@ -245,66 +267,64 @@
c = stream.readchr()
elif c == quote:
return Token(tok.STRING, atom=s)
- s += c
+ s += _chr_to_str(c)
# NUMBERS
- if c in _DIGITS or (c == '.' and stream.peekchrif(_DIGITS)):
+ if _str_has_chr(_DIGITS, c) or (c == '.' and stream.peekchrin(_DIGITS)):
s = c # TODO
- stream.watch_reads()
- if c == '0' and stream.readchrif('xX'):
+ if c == '0' and stream.readchrin('xX'):
# Hex
- while stream.readchrif(_HEX_DIGITS):
+ while stream.readchrin(_HEX_DIGITS):
pass
- elif c == '0' and stream.readchrif(_DIGITS):
+ elif c == '0' and stream.readchrin(_DIGITS):
# Octal
- while stream.readchrif(_DIGITS):
+ while stream.readchrin(_DIGITS):
pass
else:
# Decimal
if c != '.':
- while stream.readchrif(_DIGITS):
+ while stream.readchrin(_DIGITS):
pass
stream.readchrif('.')
- while stream.readchrif(_DIGITS):
+ while stream.readchrin(_DIGITS):
pass
- if stream.readchrif('eE'):
- stream.readchrif('+-')
- if not stream.readchrif(_DIGITS):
+ if stream.readchrin('eE'):
+ stream.readchrin('+-')
+ if not stream.readchrin(_DIGITS):
raise JSSyntaxError(stream.get_offset(), 'syntax_error')
- while stream.readchrif(_DIGITS):
+ while stream.readchrin(_DIGITS):
pass
- if stream.peekchrif(_IDENT):
+ if stream.peekchrin(_IDENT):
return Token(tok.ERROR)
- atom = s + stream.get_watched_reads()
+ atom = stream.get_watched_reads()
return Token(tok.NUMBER, atom=atom)
if c in _PUNCTUATOR_TREE:
d = _PUNCTUATOR_TREE[c]
while True:
- c = stream.readchrif(list(d.keys()))
+ c = stream.readchrin(u''.join(d.keys()))
if c:
d = d[c]
else:
break
try:
- return Token(d[None])
+ return Token(d[''])
except KeyError:
print('oops')
raise JSSyntaxError(stream.get_offset(), 'syntax_error')
- if c in _IDENT:
- s = ''
- while c:
- s += c
- c = stream.readchrif(_IDENT + _DIGITS)
- if s in _KEYWORDS:
- return Token(_KEYWORDS[s], atom=s)
- elif s:
- return Token(tok.NAME, atom=s)
+ if _str_has_chr(_IDENT, c):
+ while stream.readchrin(_IDENT + _DIGITS):
+ pass
+ atom = stream.get_watched_reads()
+ if atom in _KEYWORDS:
+ return Token(_KEYWORDS[atom], atom=atom)
+ return Token(tok.NAME, atom=atom)
+
raise JSSyntaxError(stream.get_offset(), 'unexpected_char',
- { 'char': c })
+ { 'char': _chr_to_str(c) })
Modified: trunk/jsengine/tokenizer/tok.py
===================================================================
--- trunk/jsengine/tokenizer/tok.py 2013-10-09 21:51:03 UTC (rev 341)
+++ trunk/jsengine/tokenizer/tok.py 2013-10-09 22:41:46 UTC (rev 342)
@@ -123,6 +123,6 @@
for c in punctuator.literal:
leaf = leaf.setdefault(c, {})
assert not None in leaf, punctuator.literal
- leaf[None] = punctuator
+ leaf[''] = punctuator
return tree
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2013-10-09 21:51:05
|
Revision: 341
http://sourceforge.net/p/javascriptlint/code/341
Author: matthiasmiller
Date: 2013-10-09 21:51:03 +0000 (Wed, 09 Oct 2013)
Log Message:
-----------
Remove unused parameters from Tokenizer.advance
Modified Paths:
--------------
trunk/jsengine/tokenizer/__init__.py
Modified: trunk/jsengine/tokenizer/__init__.py
===================================================================
--- trunk/jsengine/tokenizer/__init__.py 2013-10-09 21:34:59 UTC (rev 340)
+++ trunk/jsengine/tokenizer/__init__.py 2013-10-09 21:51:03 UTC (rev 341)
@@ -96,23 +96,16 @@
else:
return peek
- def advance(self, skipspace=True, skipcomments=True):
+ def advance(self):
assert not self._error
self._readahead()
- for i, peek in enumerate(self._peeked):
- if not skipspace and peek.tok in (tok.EOL, tok.SPACE):
- self._peeked = self._peeked[i+1:]
- return peek
- elif not skipcomments and peek.tok in (tok.C_COMMENT, tok.CPP_COMMENT, tok.HTML_COMMENT):
- self._peeked = self._peeked[i+1:]
- return peek
- else:
- self._peeked = []
- if peek.tok == tok.ERROR:
- self._error = True
- raise JSSyntaxError(peek.start_offset, peek.atom or 'syntax_error')
- return peek
+ peek = self._peeked[-1]
+ self._peeked = []
+ if peek.tok == tok.ERROR:
+ self._error = True
+ raise JSSyntaxError(peek.start_offset, peek.atom or 'syntax_error')
+ return peek
def next_withregexp(self):
assert not self._error
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2013-10-09 21:35:02
|
Revision: 340
http://sourceforge.net/p/javascriptlint/code/340
Author: matthiasmiller
Date: 2013-10-09 21:34:59 +0000 (Wed, 09 Oct 2013)
Log Message:
-----------
Move tokens into separate module
Modified Paths:
--------------
trunk/jsengine/tokenizer/__init__.py
Added Paths:
-----------
trunk/jsengine/tokenizer/tok.py
Modified: trunk/jsengine/tokenizer/__init__.py
===================================================================
--- trunk/jsengine/tokenizer/__init__.py 2013-10-09 20:33:12 UTC (rev 339)
+++ trunk/jsengine/tokenizer/__init__.py 2013-10-09 21:34:59 UTC (rev 340)
@@ -1,5 +1,6 @@
# vim: sw=4 ts=4 et
from jsengine import JSSyntaxError
+import tok
_WHITESPACE = u'\u0020\t\u000B\u000C\u00A0\uFFFF'
_LINETERMINATOR = u'\u000A\u000D\u2028\u2029'
@@ -10,131 +11,9 @@
u'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + \
u'$_'
-_ALL_TOKENS = []
+_KEYWORDS = tok.getkeywords()
+_PUNCTUATOR_TREE = tok.get_punctuator_tree()
-class _Token(object):
- def __init__(self, category, literal):
- self._category = category
- self._literal = literal
- _ALL_TOKENS.append(self)
-
- def __repr__(self):
- return '_Token(%r, %r)' % (self._category, self._literal)
-
- @property
- def category(self):
- return self._category
-
- @property
- def literal(self):
- return self._literal
-
-class _Tokens(object):
- # Symbols
- ASSIGN_ULSHIFT = _Token('sym', '<<<=')
- ASSIGN_URSHIFT = _Token('sym', '>>>=')
- EQ_STRICT = _Token('sym', '===')
- NE_STRICT = _Token('sym', '!==')
- URSHIFT = _Token('sym', '>>>')
- ASSIGN_LSHIFT = _Token('sym', '<<=')
- ASSIGN_RSHIFT = _Token('sym', '>>=')
- LE = _Token('sym', '<=')
- GE = _Token('sym', '>=')
- EQ = _Token('sym', '==')
- NE = _Token('sym', '!=')
- INC = _Token('sym', '++')
- DEC = _Token('sym', '--')
- LSHIFT = _Token('sym', '<<')
- RSHIFT = _Token('sym', '>>')
- LOGICAL_AND = _Token('sym', '&&')
- LOGICAL_OR = _Token('sym', '||')
- ASSIGN_ADD = _Token('sym', '+=')
- ASSIGN_SUB = _Token('sym', '-=')
- ASSIGN_MUL = _Token('sym', '*=')
- ASSIGN_MOD = _Token('sym', '%=')
- ASSIGN_BIT_AND = _Token('sym', '&=')
- ASSIGN_BIT_OR = _Token('sym', '|=')
- ASSIGN_BIT_XOR = _Token('sym', '^=')
- ASSIGN_DIV = _Token('sym', '/=')
- LBRACE = _Token('sym', '{')
- RBRACE = _Token('sym', '}')
- LPAREN = _Token('sym', '(')
- RPAREN = _Token('sym', ')')
- LBRACKET = _Token('sym', '[')
- RBRACKET = _Token('sym', ']')
- DOT = _Token('sym', '.')
- SEMI = _Token('sym', ';')
- COMMA = _Token('sym', ',')
- LT = _Token('sym', '<')
- GT = _Token('sym', '>')
- ADD = _Token('sym', '+')
- SUB = _Token('sym', '-')
- MUL = _Token('sym', '*')
- MOD = _Token('sym', '%')
- BIT_OR = _Token('sym', '|')
- BIT_AND = _Token('sym', '&')
- BIT_XOR = _Token('sym', '^')
- LOGICAL_NOT = _Token('sym', '!')
- BIT_NOT = _Token('sym', '~')
- QUESTION = _Token('sym', '?')
- COLON = _Token('sym', ':')
- ASSIGN = _Token('sym', '=')
- DIV = _Token('sym', '/')
-
- # Keywords
- BREAK = _Token('kw', 'break')
- CASE = _Token('kw', 'case')
- CATCH = _Token('kw', 'catch')
- CONTINUE = _Token('kw', 'continue')
- DEFAULT = _Token('kw', 'default')
- DELETE = _Token('kw', 'delete')
- DO = _Token('kw', 'do')
- ELSE = _Token('kw', 'else')
- FALSE = _Token('kw', 'false')
- FINALLY = _Token('kw', 'finally')
- FOR = _Token('kw', 'for')
- FUNCTION = _Token('kw', 'function')
- IF = _Token('kw', 'if')
- IN = _Token('kw', 'in')
- INSTANCEOF = _Token('kw', 'instanceof')
- NEW = _Token('kw', 'new')
- NULL = _Token('kw', 'null')
- RETURN = _Token('kw', 'return')
- SWITCH = _Token('kw', 'switch')
- THIS = _Token('kw', 'this')
- THROW = _Token('kw', 'throw')
- TRUE = _Token('kw', 'true')
- TYPEOF = _Token('kw', 'typeof')
- TRY = _Token('kw', 'try')
- VAR = _Token('kw', 'var')
- VOID = _Token('kw', 'void')
- WHILE = _Token('kw', 'while')
- WITH = _Token('kw', 'with')
-
- # Other tokens
- C_COMMENT = _Token('other', '/*')
- CPP_COMMENT = _Token('other', '//')
- HTML_COMMENT = _Token('other', '<!--')
- ERROR = _Token('other', 'err')
- EOF = _Token('other', 'eof')
- EOL = _Token('other', 'eol')
- NAME = _Token('other', '(name)')
- NUMBER = _Token('other', '(num)')
- OPERATOR = _Token('other', '(op)')
- REGEXP = _Token('other', '(re)')
- SPACE = _Token('other', '(sp)')
- STRING = _Token('other', '(str)')
-
-tok = _Tokens()
-_KEYWORDS = dict((t.literal, t) for t in _ALL_TOKENS if t.category == 'kw')
-_PUNCTUATOR_TREE = {}
-for punctuator in (t for t in _ALL_TOKENS if t.category == 'sym'):
- d = _PUNCTUATOR_TREE
- for c in punctuator.literal:
- d = d.setdefault(c, {})
- assert not None in d, punctuator.literal
- d[None] = punctuator
-
class Token:
def __init__(self, tok, atom=None):
self.tok = tok
@@ -282,7 +161,7 @@
peek.set_offset(start_offset, end_offset)
self._peeked.append(peek)
- assert isinstance(peek.tok, _Token), repr(peek.tok)
+ assert isinstance(peek.tok, tok.TokenType), repr(peek.tok)
if peek.tok not in (tok.EOL, tok.SPACE,
tok.C_COMMENT, tok.CPP_COMMENT,
tok.HTML_COMMENT):
Copied: trunk/jsengine/tokenizer/tok.py (from rev 339, trunk/jsengine/tokenizer/__init__.py)
===================================================================
--- trunk/jsengine/tokenizer/tok.py (rev 0)
+++ trunk/jsengine/tokenizer/tok.py 2013-10-09 21:34:59 UTC (rev 340)
@@ -0,0 +1,128 @@
+# vim: sw=4 ts=4 et
+_ALL_TOKENS = []
+
+class TokenType(object):
+ def __init__(self, category, literal):
+ self._category = category
+ self._literal = literal
+ _ALL_TOKENS.append(self)
+
+ def __repr__(self):
+ return 'TokenType(%r, %r)' % (self._category, self._literal)
+
+ @property
+ def category(self):
+ return self._category
+
+ @property
+ def literal(self):
+ return self._literal
+
+# Symbols
+ASSIGN_ULSHIFT = TokenType('sym', '<<<=')
+ASSIGN_URSHIFT = TokenType('sym', '>>>=')
+EQ_STRICT = TokenType('sym', '===')
+NE_STRICT = TokenType('sym', '!==')
+URSHIFT = TokenType('sym', '>>>')
+ASSIGN_LSHIFT = TokenType('sym', '<<=')
+ASSIGN_RSHIFT = TokenType('sym', '>>=')
+LE = TokenType('sym', '<=')
+GE = TokenType('sym', '>=')
+EQ = TokenType('sym', '==')
+NE = TokenType('sym', '!=')
+INC = TokenType('sym', '++')
+DEC = TokenType('sym', '--')
+LSHIFT = TokenType('sym', '<<')
+RSHIFT = TokenType('sym', '>>')
+LOGICAL_AND = TokenType('sym', '&&')
+LOGICAL_OR = TokenType('sym', '||')
+ASSIGN_ADD = TokenType('sym', '+=')
+ASSIGN_SUB = TokenType('sym', '-=')
+ASSIGN_MUL = TokenType('sym', '*=')
+ASSIGN_MOD = TokenType('sym', '%=')
+ASSIGN_BIT_AND = TokenType('sym', '&=')
+ASSIGN_BIT_OR = TokenType('sym', '|=')
+ASSIGN_BIT_XOR = TokenType('sym', '^=')
+ASSIGN_DIV = TokenType('sym', '/=')
+LBRACE = TokenType('sym', '{')
+RBRACE = TokenType('sym', '}')
+LPAREN = TokenType('sym', '(')
+RPAREN = TokenType('sym', ')')
+LBRACKET = TokenType('sym', '[')
+RBRACKET = TokenType('sym', ']')
+DOT = TokenType('sym', '.')
+SEMI = TokenType('sym', ';')
+COMMA = TokenType('sym', ',')
+LT = TokenType('sym', '<')
+GT = TokenType('sym', '>')
+ADD = TokenType('sym', '+')
+SUB = TokenType('sym', '-')
+MUL = TokenType('sym', '*')
+MOD = TokenType('sym', '%')
+BIT_OR = TokenType('sym', '|')
+BIT_AND = TokenType('sym', '&')
+BIT_XOR = TokenType('sym', '^')
+LOGICAL_NOT = TokenType('sym', '!')
+BIT_NOT = TokenType('sym', '~')
+QUESTION = TokenType('sym', '?')
+COLON = TokenType('sym', ':')
+ASSIGN = TokenType('sym', '=')
+DIV = TokenType('sym', '/')
+
+# Keywords
+BREAK = TokenType('kw', 'break')
+CASE = TokenType('kw', 'case')
+CATCH = TokenType('kw', 'catch')
+CONTINUE = TokenType('kw', 'continue')
+DEFAULT = TokenType('kw', 'default')
+DELETE = TokenType('kw', 'delete')
+DO = TokenType('kw', 'do')
+ELSE = TokenType('kw', 'else')
+FALSE = TokenType('kw', 'false')
+FINALLY = TokenType('kw', 'finally')
+FOR = TokenType('kw', 'for')
+FUNCTION = TokenType('kw', 'function')
+IF = TokenType('kw', 'if')
+IN = TokenType('kw', 'in')
+INSTANCEOF = TokenType('kw', 'instanceof')
+NEW = TokenType('kw', 'new')
+NULL = TokenType('kw', 'null')
+RETURN = TokenType('kw', 'return')
+SWITCH = TokenType('kw', 'switch')
+THIS = TokenType('kw', 'this')
+THROW = TokenType('kw', 'throw')
+TRUE = TokenType('kw', 'true')
+TYPEOF = TokenType('kw', 'typeof')
+TRY = TokenType('kw', 'try')
+VAR = TokenType('kw', 'var')
+VOID = TokenType('kw', 'void')
+WHILE = TokenType('kw', 'while')
+WITH = TokenType('kw', 'with')
+
+# Other tokens
+C_COMMENT = TokenType('other', '/*')
+CPP_COMMENT = TokenType('other', '//')
+HTML_COMMENT = TokenType('other', '<!--')
+ERROR = TokenType('other', 'err')
+EOF = TokenType('other', 'eof')
+EOL = TokenType('other', 'eol')
+NAME = TokenType('other', '(name)')
+NUMBER = TokenType('other', '(num)')
+OPERATOR = TokenType('other', '(op)')
+REGEXP = TokenType('other', '(re)')
+SPACE = TokenType('other', '(sp)')
+STRING = TokenType('other', '(str)')
+
+def getkeywords():
+ return dict((t.literal, t) for t in _ALL_TOKENS if t.category == 'kw')
+
+def get_punctuator_tree():
+ tree = {}
+ for punctuator in (t for t in _ALL_TOKENS if t.category == 'sym'):
+ leaf = tree
+ for c in punctuator.literal:
+ leaf = leaf.setdefault(c, {})
+ assert not None in leaf, punctuator.literal
+ leaf[None] = punctuator
+ return tree
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2013-10-09 20:33:14
|
Revision: 339
http://sourceforge.net/p/javascriptlint/code/339
Author: matthiasmiller
Date: 2013-10-09 20:33:12 +0000 (Wed, 09 Oct 2013)
Log Message:
-----------
Simplify TokenStream.get_offset
Modified Paths:
--------------
trunk/jsengine/tokenizer/__init__.py
Modified: trunk/jsengine/tokenizer/__init__.py
===================================================================
--- trunk/jsengine/tokenizer/__init__.py 2013-10-09 20:30:33 UTC (rev 338)
+++ trunk/jsengine/tokenizer/__init__.py 2013-10-09 20:33:12 UTC (rev 339)
@@ -156,8 +156,8 @@
self._offset = 0
self._watched_offset = None
- def get_offset(self, offset=0):
- return self._start_offset + self._offset + offset
+ def get_offset(self):
+ return self._start_offset + self._offset
def watch_reads(self):
self._watched_offset = self._offset
@@ -175,7 +175,7 @@
if self._offset < len(self._content):
self._offset += 1
return self._content[self._offset - 1]
- raise JSSyntaxError(self.get_offset(-1), 'unexpected_eof')
+ raise JSSyntaxError(self.get_offset()-1, 'unexpected_eof')
def readchrif(self, seq):
s = self.peekchrif(seq)
@@ -240,7 +240,7 @@
self._readahead()
if self._peeked[-1].tok == tok.DIV:
token = self._parse_rest_of_regexp()
- token.set_offset(self._peeked[-1].start_offset, self._stream.get_offset(-1))
+ token.set_offset(self._peeked[-1].start_offset, self._stream.get_offset()-1)
self._peeked = []
if token.tok == tok.ERROR:
self._error = True
@@ -275,7 +275,7 @@
while True:
start_offset = self._stream.get_offset()
peek = self._next()
- end_offset = self._stream.get_offset(-1)
+ end_offset = self._stream.get_offset()-1
if peek.tok == tok.ERROR:
peek.set_offset(end_offset, end_offset)
else:
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2013-10-09 20:30:38
|
Revision: 338
http://sourceforge.net/p/javascriptlint/code/338
Author: matthiasmiller
Date: 2013-10-09 20:30:33 +0000 (Wed, 09 Oct 2013)
Log Message:
-----------
Tweak to _Tokens object
Modified Paths:
--------------
trunk/jsengine/tokenizer/__init__.py
Modified: trunk/jsengine/tokenizer/__init__.py
===================================================================
--- trunk/jsengine/tokenizer/__init__.py 2013-10-09 20:21:32 UTC (rev 337)
+++ trunk/jsengine/tokenizer/__init__.py 2013-10-09 20:30:33 UTC (rev 338)
@@ -30,101 +30,100 @@
return self._literal
class _Tokens(object):
- def __init__(self):
- # Load symbols
- self.ASSIGN_ULSHIFT = _Token('sym', '<<<=')
- self.ASSIGN_URSHIFT = _Token('sym', '>>>=')
- self.EQ_STRICT = _Token('sym', '===')
- self.NE_STRICT = _Token('sym', '!==')
- self.URSHIFT = _Token('sym', '>>>')
- self.ASSIGN_LSHIFT = _Token('sym', '<<=')
- self.ASSIGN_RSHIFT = _Token('sym', '>>=')
- self.LE = _Token('sym', '<=')
- self.GE = _Token('sym', '>=')
- self.EQ = _Token('sym', '==')
- self.NE = _Token('sym', '!=')
- self.INC = _Token('sym', '++')
- self.DEC = _Token('sym', '--')
- self.LSHIFT = _Token('sym', '<<')
- self.RSHIFT = _Token('sym', '>>')
- self.LOGICAL_AND = _Token('sym', '&&')
- self.LOGICAL_OR = _Token('sym', '||')
- self.ASSIGN_ADD = _Token('sym', '+=')
- self.ASSIGN_SUB = _Token('sym', '-=')
- self.ASSIGN_MUL = _Token('sym', '*=')
- self.ASSIGN_MOD = _Token('sym', '%=')
- self.ASSIGN_BIT_AND = _Token('sym', '&=')
- self.ASSIGN_BIT_OR = _Token('sym', '|=')
- self.ASSIGN_BIT_XOR = _Token('sym', '^=')
- self.ASSIGN_DIV = _Token('sym', '/=')
- self.LBRACE = _Token('sym', '{')
- self.RBRACE = _Token('sym', '}')
- self.LPAREN = _Token('sym', '(')
- self.RPAREN = _Token('sym', ')')
- self.LBRACKET = _Token('sym', '[')
- self.RBRACKET = _Token('sym', ']')
- self.DOT = _Token('sym', '.')
- self.SEMI = _Token('sym', ';')
- self.COMMA = _Token('sym', ',')
- self.LT = _Token('sym', '<')
- self.GT = _Token('sym', '>')
- self.ADD = _Token('sym', '+')
- self.SUB = _Token('sym', '-')
- self.MUL = _Token('sym', '*')
- self.MOD = _Token('sym', '%')
- self.BIT_OR = _Token('sym', '|')
- self.BIT_AND = _Token('sym', '&')
- self.BIT_XOR = _Token('sym', '^')
- self.LOGICAL_NOT = _Token('sym', '!')
- self.BIT_NOT = _Token('sym', '~')
- self.QUESTION = _Token('sym', '?')
- self.COLON = _Token('sym', ':')
- self.ASSIGN = _Token('sym', '=')
- self.DIV = _Token('sym', '/')
+ # Symbols
+ ASSIGN_ULSHIFT = _Token('sym', '<<<=')
+ ASSIGN_URSHIFT = _Token('sym', '>>>=')
+ EQ_STRICT = _Token('sym', '===')
+ NE_STRICT = _Token('sym', '!==')
+ URSHIFT = _Token('sym', '>>>')
+ ASSIGN_LSHIFT = _Token('sym', '<<=')
+ ASSIGN_RSHIFT = _Token('sym', '>>=')
+ LE = _Token('sym', '<=')
+ GE = _Token('sym', '>=')
+ EQ = _Token('sym', '==')
+ NE = _Token('sym', '!=')
+ INC = _Token('sym', '++')
+ DEC = _Token('sym', '--')
+ LSHIFT = _Token('sym', '<<')
+ RSHIFT = _Token('sym', '>>')
+ LOGICAL_AND = _Token('sym', '&&')
+ LOGICAL_OR = _Token('sym', '||')
+ ASSIGN_ADD = _Token('sym', '+=')
+ ASSIGN_SUB = _Token('sym', '-=')
+ ASSIGN_MUL = _Token('sym', '*=')
+ ASSIGN_MOD = _Token('sym', '%=')
+ ASSIGN_BIT_AND = _Token('sym', '&=')
+ ASSIGN_BIT_OR = _Token('sym', '|=')
+ ASSIGN_BIT_XOR = _Token('sym', '^=')
+ ASSIGN_DIV = _Token('sym', '/=')
+ LBRACE = _Token('sym', '{')
+ RBRACE = _Token('sym', '}')
+ LPAREN = _Token('sym', '(')
+ RPAREN = _Token('sym', ')')
+ LBRACKET = _Token('sym', '[')
+ RBRACKET = _Token('sym', ']')
+ DOT = _Token('sym', '.')
+ SEMI = _Token('sym', ';')
+ COMMA = _Token('sym', ',')
+ LT = _Token('sym', '<')
+ GT = _Token('sym', '>')
+ ADD = _Token('sym', '+')
+ SUB = _Token('sym', '-')
+ MUL = _Token('sym', '*')
+ MOD = _Token('sym', '%')
+ BIT_OR = _Token('sym', '|')
+ BIT_AND = _Token('sym', '&')
+ BIT_XOR = _Token('sym', '^')
+ LOGICAL_NOT = _Token('sym', '!')
+ BIT_NOT = _Token('sym', '~')
+ QUESTION = _Token('sym', '?')
+ COLON = _Token('sym', ':')
+ ASSIGN = _Token('sym', '=')
+ DIV = _Token('sym', '/')
- # Load keywords
- self.BREAK = _Token('kw', 'break')
- self.CASE = _Token('kw', 'case')
- self.CATCH = _Token('kw', 'catch')
- self.CONTINUE = _Token('kw', 'continue')
- self.DEFAULT = _Token('kw', 'default')
- self.DELETE = _Token('kw', 'delete')
- self.DO = _Token('kw', 'do')
- self.ELSE = _Token('kw', 'else')
- self.FALSE = _Token('kw', 'false')
- self.FINALLY = _Token('kw', 'finally')
- self.FOR = _Token('kw', 'for')
- self.FUNCTION = _Token('kw', 'function')
- self.IF = _Token('kw', 'if')
- self.IN = _Token('kw', 'in')
- self.INSTANCEOF = _Token('kw', 'instanceof')
- self.NEW = _Token('kw', 'new')
- self.NULL = _Token('kw', 'null')
- self.RETURN = _Token('kw', 'return')
- self.SWITCH = _Token('kw', 'switch')
- self.THIS = _Token('kw', 'this')
- self.THROW = _Token('kw', 'throw')
- self.TRUE = _Token('kw', 'true')
- self.TYPEOF = _Token('kw', 'typeof')
- self.TRY = _Token('kw', 'try')
- self.VAR = _Token('kw', 'var')
- self.VOID = _Token('kw', 'void')
- self.WHILE = _Token('kw', 'while')
- self.WITH = _Token('kw', 'with')
+ # Keywords
+ BREAK = _Token('kw', 'break')
+ CASE = _Token('kw', 'case')
+ CATCH = _Token('kw', 'catch')
+ CONTINUE = _Token('kw', 'continue')
+ DEFAULT = _Token('kw', 'default')
+ DELETE = _Token('kw', 'delete')
+ DO = _Token('kw', 'do')
+ ELSE = _Token('kw', 'else')
+ FALSE = _Token('kw', 'false')
+ FINALLY = _Token('kw', 'finally')
+ FOR = _Token('kw', 'for')
+ FUNCTION = _Token('kw', 'function')
+ IF = _Token('kw', 'if')
+ IN = _Token('kw', 'in')
+ INSTANCEOF = _Token('kw', 'instanceof')
+ NEW = _Token('kw', 'new')
+ NULL = _Token('kw', 'null')
+ RETURN = _Token('kw', 'return')
+ SWITCH = _Token('kw', 'switch')
+ THIS = _Token('kw', 'this')
+ THROW = _Token('kw', 'throw')
+ TRUE = _Token('kw', 'true')
+ TYPEOF = _Token('kw', 'typeof')
+ TRY = _Token('kw', 'try')
+ VAR = _Token('kw', 'var')
+ VOID = _Token('kw', 'void')
+ WHILE = _Token('kw', 'while')
+ WITH = _Token('kw', 'with')
- # Load other tokens
- self.C_COMMENT = _Token('other', '/*')
- self.CPP_COMMENT = _Token('other', '//')
- self.HTML_COMMENT = _Token('other', '<!--')
- self.ERROR = _Token('other', 'err')
- self.EOF = _Token('other', 'eof')
- self.EOL = _Token('other', 'eol')
- self.NAME = _Token('other', '(name)')
- self.NUMBER = _Token('other', '(num)')
- self.OPERATOR = _Token('other', '(op)')
- self.REGEXP = _Token('other', '(re)')
- self.SPACE = _Token('other', '(sp)')
- self.STRING = _Token('other', '(str)')
+ # Other tokens
+ C_COMMENT = _Token('other', '/*')
+ CPP_COMMENT = _Token('other', '//')
+ HTML_COMMENT = _Token('other', '<!--')
+ ERROR = _Token('other', 'err')
+ EOF = _Token('other', 'eof')
+ EOL = _Token('other', 'eol')
+ NAME = _Token('other', '(name)')
+ NUMBER = _Token('other', '(num)')
+ OPERATOR = _Token('other', '(op)')
+ REGEXP = _Token('other', '(re)')
+ SPACE = _Token('other', '(sp)')
+ STRING = _Token('other', '(str)')
tok = _Tokens()
_KEYWORDS = dict((t.literal, t) for t in _ALL_TOKENS if t.category == 'kw')
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|