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. |