[javascriptlint-commit] SF.net SVN: javascriptlint: [149] trunk
Status: Beta
Brought to you by:
matthiasmiller
From: <mat...@us...> - 2008-03-01 18:44:55
|
Revision: 149 http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=149&view=rev Author: matthiasmiller Date: 2008-03-01 10:44:53 -0800 (Sat, 01 Mar 2008) Log Message: ----------- use numbers instead of strings for Node.kind and Node.opcode Modified Paths: -------------- trunk/pyjsl/lint.py trunk/pyjsl/parse.py trunk/pyjsl/warnings.py trunk/pyspidermonkey/pyspidermonkey.c Modified: trunk/pyjsl/lint.py =================================================================== --- trunk/pyjsl/lint.py 2008-03-01 17:32:55 UTC (rev 148) +++ trunk/pyjsl/lint.py 2008-03-01 18:44:53 UTC (rev 149) @@ -8,6 +8,8 @@ import warnings import util +from pyspidermonkey import tok, op + _newline_kinds = ( 'eof', 'comma', 'dot', 'semi', 'colon', 'lc', 'rc', 'lp', 'rb', 'assign', 'relop', 'hook', 'plus', 'minus', 'star', 'divop', 'eqop', 'shop', 'or', @@ -29,14 +31,14 @@ _identifier = re.compile('^[A-Za-z_$][A-Za-z0-9_$]*$') def _find_function(node): - while node and node.kind != 'function': + while node and node.kind != tok.FUNCTION: node = node.parent return node def _find_functions(node): functions = [] while node: - if node.kind == 'function': + if node.kind == tok.FUNCTION: functions.append(node) node = node.parent return functions @@ -70,7 +72,7 @@ class Scope(): def __init__(self, node): - self._is_with_scope = node.kind == 'with' + self._is_with_scope = node.kind == tok.WITH self._parent = None self._kids = [] self._identifiers = {} @@ -244,7 +246,7 @@ def warn_or_declare(name, node): other = scope.get_identifier(name) - if other and other.kind == 'function' and name in other.fn_args: + if other and other.kind == tok.FUNCTION and name in other.fn_args: report(node, 'var_hides_arg') elif other: report(node, 'redeclared_var') @@ -252,34 +254,34 @@ scope.add_declaration(name, node) # Let the visitors warn. - for kind in (node.kind, '%s:%s' % (node.kind, node.opcode)): + for kind in (node.kind, (node.kind, node.opcode)): if kind in visitors: for visitor in visitors[kind]: warning_node = visitor(node) if warning_node: report(warning_node, visitor.im_class.__name__) - if node.kind == 'name': - if node.node_index == 0 and node.parent.kind == 'colon' and node.parent.parent.kind == 'rc': + if node.kind == tok.NAME: + if node.node_index == 0 and node.parent.kind == tok.COLON and node.parent.parent.kind == tok.RC: pass # left side of object literal - elif node.parent.kind == 'catch': + elif node.parent.kind == tok.CATCH: scope.add_declaration(node.atom, node) else: scope.add_reference(node.atom, node) # Push function identifiers - if node.kind == 'function': + if node.kind == tok.FUNCTION: if node.fn_name: warn_or_declare(node.fn_name, node) scope = scope.add_scope(node) for var_name in node.fn_args: scope.add_declaration(var_name, node) - elif node.kind == 'lexicalscope': + elif node.kind == tok.LEXICALSCOPE: scope = scope.add_scope(node) - elif node.kind == 'with': + elif node.kind == tok.WITH: scope = scope.add_scope(node) - if node.parent and node.parent.kind == 'var': + if node.parent and node.parent.kind == tok.VAR: warn_or_declare(node.atom, node) for child in node.kids: Modified: trunk/pyjsl/parse.py =================================================================== --- trunk/pyjsl/parse.py 2008-03-01 17:32:55 UTC (rev 148) +++ trunk/pyjsl/parse.py 2008-03-01 18:44:53 UTC (rev 149) @@ -5,6 +5,7 @@ import unittest import pyspidermonkey +from pyspidermonkey import tok, op class NodePos(): def __init__(self, line, col): @@ -73,10 +74,8 @@ def _to_node(kid): if kid: return _Node(kid) - kwargs['type'] = kwargs['type'].lower() self.kind = kwargs['type'] - assert kwargs['opcode'].startswith('JSOP_') - kwargs['opcode'] = kwargs['opcode'][5:].lower() + kwargs['opcode'] = kwargs['opcode'] self.opcode = kwargs['opcode'] self.kids = tuple([_to_node(kid) for kid in kwargs['kids']]) for kid in self.kids: @@ -127,9 +126,9 @@ # Bail out for functions if not are_functions_equiv: - if self.kind == 'function': + if self.kind == tok.FUNCTION: return False - if self.kind == 'lp' and self.opcode == 'call': + if self.kind == tok.LP and self.opcode == op.CALL: return False if self.kind != other.kind: @@ -138,11 +137,11 @@ return False # Check atoms on names, properties, and string constants - if self.kind in ('name', 'dot', 'string') and self.atom != other.atom: + if self.kind in (tok.NAME, tok.DOT, tok.STRING) and self.atom != other.atom: return False # Check values on numbers - if self.kind == 'number' and self.dval != other.dval: + if self.kind == tok.NUMBER and self.dval != other.dval: return False # Compare child nodes @@ -179,6 +178,7 @@ else: comment_text = comment_text[2:] opcode = 'JSOP_CPP_COMMENT' + opcode = opcode[5:].lower() start_offset = match.start()+1 end_offset = match.end() @@ -216,10 +216,10 @@ nodes = [] comment_ignore_ranges = NodeRanges() def process(node): - if node.kind == 'number': + if node.kind == tok.NUMBER: node.atom = positions.text(node.start_pos(), node.end_pos()) - elif node.kind == 'string' or \ - (node.kind == 'object' and node.opcode == 'regexp'): + elif node.kind == tok.STRING or \ + (node.kind == tok.OBJECT and node.opcode == op.REGEXP): start_offset = positions.to_offset(node.start_pos()) end_offset = positions.to_offset(node.end_pos()) comment_ignore_ranges.add(start_offset, end_offset) Modified: trunk/pyjsl/warnings.py =================================================================== --- trunk/pyjsl/warnings.py 2008-03-01 17:32:55 UTC (rev 148) +++ trunk/pyjsl/warnings.py 2008-03-01 18:44:53 UTC (rev 149) @@ -4,7 +4,7 @@ The class can have one more more member functions to inspect nodes. The function should be decorated with a @lookat call specifying the nodes it -wants to examine. The node names may be in the 'kind' or 'kind:opcode' +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 return the node causing the warning. @@ -12,7 +12,7 @@ class warning_name: 'questionable JavaScript coding style' - @lookat('nodekind', 'nodekind:opcode') + @lookat(tok.NODEKIND, (tok.NODEKIND, op.OPCODE)) def _lint(self, node): if questionable: return node @@ -22,17 +22,19 @@ import types from visitation import visit as lookat +from pyspidermonkey import tok, op + # TODO: document inspect, node:opcode, etc def _get_branch_in_for(node): " Returns None if this is not one of the branches in a 'for' " - if node.parent and node.parent.kind == 'reserved' and \ - node.parent.parent.kind == 'for': + if node.parent and node.parent.kind == tok.RESERVED and \ + node.parent.parent.kind == tok.FOR: return node.node_index return None def _get_exit_points(node): - if node.kind == 'lc': + if node.kind == tok.LC: # Only if the last child contains it exit_points = set([None]) for kid in node.kids: @@ -41,13 +43,13 @@ exit_points.remove(None) if kid: exit_points |= _get_exit_points(kid) - elif node.kind == 'if': + elif node.kind == tok.IF: # Only if both branches have an exit point cond_, if_, else_ = node.kids exit_points = _get_exit_points(if_) if else_: exit_points |= _get_exit_points(else_) - elif node.kind == 'switch': + elif node.kind == tok.SWITCH: exit_points = set([None]) switch_has_default = False @@ -57,7 +59,7 @@ 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 == 'default' + 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 @@ -65,8 +67,8 @@ exit_points.remove(None) # Check if the switch contained any break - if 'break' in exit_points: - exit_points.remove('break') + if tok.BREAK in exit_points: + exit_points.remove(tok.BREAK) exit_points.add(None) # Check if the switch had a default case @@ -76,15 +78,15 @@ # Check if the final case statement had a fallthru if switch_has_final_fallthru: exit_points.add(None) - elif node.kind == 'break': - exit_points = set(['break']) - elif node.kind == 'with': + elif node.kind == tok.BREAK: + exit_points = set([tok.BREAK]) + elif node.kind == tok.WITH: exit_points = _get_exit_points(node.kids[-1]) - elif node.kind == 'return': - exit_points = set(['return']) - elif node.kind == 'throw': - exit_points = set(['throw']) - elif node.kind == 'try': + elif node.kind == tok.RETURN: + exit_points = set([tok.RETURN]) + elif node.kind == tok.THROW: + exit_points = set([tok.THROW]) + elif node.kind == tok.TRY: try_, catch_, finally_ = node.kids exit_points = _get_exit_points(try_) | _get_exit_points(catch_) @@ -100,24 +102,24 @@ class comparison_type_conv: 'comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)' - @lookat('eqop:eq') + @lookat((tok.EQOP, op.EQ)) def _lint(self, node): lvalue, rvalue = node.kids if not self._allow_coercive_compare(lvalue) or \ not self._allow_coercive_compare(rvalue): return node def _allow_coercive_compare(self, node): - if node.kind == 'primary' and node.opcode in ('null', 'true', 'false'): + if node.kind == tok.PRIMARY and node.opcode in (op.NULL, op.TRUE, op.FALSE): return False - if node.kind == 'number' and not node.dval: + if node.kind == tok.NUMBER and not node.dval: return False - if node.kind == 'string' and not node.atom: + if node.kind == tok.STRING and not node.atom: return False return True class default_not_at_end: 'the default case is not at the end of the switch statement' - @lookat('default') + @lookat(tok.DEFAULT) def _lint(self, node): siblings = node.parent.kids if node.node_index != len(siblings)-1: @@ -125,7 +127,7 @@ class duplicate_case_in_switch: 'duplicate case in switch statement' - @lookat('case') + @lookat(tok.CASE) def _lint(self, node): # Only look at previous siblings siblings = node.parent.kids @@ -133,30 +135,30 @@ # Compare values (first kid) node_value = node.kids[0] for sibling in siblings: - if sibling.kind == 'case': + if sibling.kind == tok.CASE: sibling_value = sibling.kids[0] if node_value.is_equivalent(sibling_value, True): return node class missing_default_case: 'missing default case in switch statement' - @lookat('switch') + @lookat(tok.SWITCH) def _lint(self, node): value, cases = node.kids for case in cases.kids: - if case.kind == 'default': + if case.kind == tok.DEFAULT: return return node class with_statement: 'with statement hides undeclared variables; use temporary variable instead' - @lookat('with') + @lookat(tok.WITH) def _lint(self, node): return node class useless_comparison: 'useless comparison; comparing identical expressions' - @lookat('eqop','relop') + @lookat(tok.EQOP,tok.RELOP) def _lint(self, node): lvalue, rvalue = node.kids if lvalue.is_equivalent(rvalue): @@ -164,45 +166,45 @@ class use_of_label: 'use of label' - @lookat('colon:name') + @lookat((tok.COLON, op.NAME)) def _lint(self, node): return node class meaningless_block: 'meaningless block; curly braces have no impact' - @lookat('lc') + @lookat(tok.LC) def _lint(self, node): - if node.parent and node.parent.kind == 'lc': + if node.parent and node.parent.kind == tok.LC: return node class misplaced_regex: 'regular expressions should be preceded by a left parenthesis, assignment, colon, or comma' - @lookat('object:regexp') + @lookat((tok.OBJECT, op.REGEXP)) def _lint(self, node): - if node.parent.kind == 'name' and node.parent.opcode == 'setname': + if node.parent.kind == tok.NAME and node.parent.opcode == op.SETNAME: return # Allow in var statements - if node.parent.kind == 'assign' and node.parent.opcode == 'nop': + if node.parent.kind == tok.ASSIGN and node.parent.opcode == op.NOP: return # Allow in assigns - if node.parent.kind == 'colon' and node.parent.parent.kind == 'rc': + if node.parent.kind == tok.COLON and node.parent.parent.kind == tok.RC: return # Allow in object literals - if node.parent.kind == 'lp' and node.parent.opcode == 'call': + if node.parent.kind == tok.LP and node.parent.opcode == op.CALL: return # Allow in parameters - if node.parent.kind == 'dot' and node.parent.opcode == 'getprop': + if node.parent.kind == tok.DOT and node.parent.opcode == op.GETPROP: return # Allow in /re/.property - if node.parent.kind == 'return': + if node.parent.kind == tok.RETURN: return # Allow for return values return node class assign_to_function_call: 'assignment to a function call' - @lookat('assign') + @lookat(tok.ASSIGN) def _lint(self, node): - if node.kids[0].kind == 'lp': + if node.kids[0].kind == tok.LP: return node class ambiguous_else_stmt: 'the else statement could be matched with one of multiple if statements (use curly braces to indicate intent' - @lookat('if') + @lookat(tok.IF) def _lint(self, node): # Only examine this node if it has an else statement. condition, if_, else_ = node.kids @@ -212,79 +214,79 @@ tmp = node while tmp: # Curly braces always clarify if statements. - if tmp.kind == 'lc': + if tmp.kind == tok.LC: return # Else is only ambiguous in the first branch of an if statement. - if tmp.parent.kind == 'if' and tmp.node_index == 1: + if tmp.parent.kind == tok.IF and tmp.node_index == 1: return else_ tmp = tmp.parent class block_without_braces: 'block statement without curly braces' - @lookat('if', 'while', 'do', 'for', 'with') + @lookat(tok.IF, tok.WHILE, tok.DO, tok.FOR, tok.WITH) def _lint(self, node): - if node.kids[1].kind != 'lc': + if node.kids[1].kind != tok.LC: return node.kids[1] class ambiguous_nested_stmt: 'block statements containing block statements should use curly braces to resolve ambiguity' - _block_nodes = ('if', 'while', 'do', 'for', 'with') + _block_nodes = (tok.IF, tok.WHILE, tok.DO, tok.FOR, tok.WITH) @lookat(*_block_nodes) def _lint(self, node): # Ignore "else if" - if node.kind == 'if' and node.node_index == 2 and node.parent.kind == '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 'lc'.) + # (Otherwise, the node type would be tok.LC.) if node.parent.kind in self._block_nodes: return node class inc_dec_within_stmt: 'increment (++) and decrement (--) operators used as part of greater statement' - @lookat('inc', 'dec') + @lookat(tok.INC, tok.DEC) def _lint(self, node): - if node.parent.kind == 'semi': + if node.parent.kind == tok.SEMI: return None # Allow within the third part of the "for" tmp = node - while tmp and tmp.parent and tmp.parent.kind == 'comma': + 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 == 'reserved' and \ - tmp.parent.parent.kind == 'for': + tmp.parent.kind == tok.RESERVED and \ + tmp.parent.parent.kind == tok.FOR: return None return node def _is_for_ternary_stmt(self, node, branch=None): - if node.parent and node.parent.kind == 'comma': + if node.parent and node.parent.kind == tok.COMMA: return _is_for_ternary_stmt(node.parent, branch) return node.node_index == branch and \ node.parent and \ - node.parent.kind == 'reserved' and \ - node.parent.parent.kind == 'for' + node.parent.kind == tok.RESERVED and \ + node.parent.parent.kind == tok.FOR class comma_separated_stmts: 'multiple statements separated by commas (use semicolons?)' - @lookat('comma') + @lookat(tok.COMMA) def _lint(self, 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 == 'rb': + if node.parent.kind == tok.RB: return return node class empty_statement: 'empty statement or extra semicolon' - @lookat('semi') + @lookat(tok.SEMI) def _semi(self, node): if not node.kids[0]: return node - @lookat('lc') + @lookat(tok.LC) def _lc(self, node): if node.kids: return @@ -292,19 +294,19 @@ if not node.parent: return # Some empty blocks are meaningful. - if node.parent.kind in ('catch', 'case', 'default', 'switch', 'function'): + if node.parent.kind in (tok.CATCH, tok.CASE, tok.DEFAULT, tok.SWITCH, tok.FUNCTION): return return node class missing_break: 'missing break statement' - @lookat('case', 'default') + @lookat(tok.CASE, tok.DEFAULT) def _lint(self, 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 == 'lc' + assert case_contents.kind == tok.LC # Ignore empty case statements if not case_contents.kids: return @@ -313,88 +315,88 @@ class missing_break_for_last_case: 'missing break statement for last case in switch' - @lookat('case', 'default') + @lookat(tok.CASE, tok.DEFAULT) def _lint(self, node): if node.node_index < len(node.parent.kids)-1: return case_contents = node.kids[1] - assert case_contents.kind == 'lc' + assert case_contents.kind == tok.LC if None in _get_exit_points(case_contents): return node class multiple_plus_minus: 'unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs' - @lookat('inc') + @lookat(tok.INC) def _inc(self, node): - if node.node_index == 0 and node.parent.kind == 'plus': + if node.node_index == 0 and node.parent.kind == tok.PLUS: return node - @lookat('dec') + @lookat(tok.DEC) def _dec(self, node): - if node.node_index == 0 and node.parent.kind == 'minus': + if node.node_index == 0 and node.parent.kind == tok.MINUS: return node class useless_assign: 'useless assignment' - @lookat('name:setname') + @lookat((tok.NAME, op.SETNAME)) def _lint(self, node): - if node.parent.kind == 'assign': + if node.parent.kind == tok.ASSIGN: assert node.node_index == 0 value = node.parent.kids[1] - elif node.parent.kind == 'var': + elif node.parent.kind == tok.VAR: value = node.kids[0] - if value and value.kind == 'name' and node.atom == value.atom: + if value and value.kind == tok.NAME and node.atom == value.atom: return node class unreachable_code: 'unreachable code' - @lookat('break', 'continue', 'return', 'throw') + @lookat(tok.BREAK, tok.CONTINUE, tok.RETURN, tok.THROW) def _lint(self, node): - if node.parent.kind == 'lc' and \ + if node.parent.kind == tok.LC and \ node.node_index != len(node.parent.kids)-1: return node.parent.kids[node.node_index+1] class meaningless_block: 'meaningless block; curly braces have no impact' - #TODO: @lookat('if') + #TODO: @lookat(tok.IF) def _lint(self, node): condition, if_, else_ = node.kids - if condition.kind == 'primary' and condition.opcode in ('true', 'false', 'null'): + if condition.kind == tok.PRIMARY and condition.opcode in (op.TRUE, op.FALSE, op.NULL): return condition - #TODO: @lookat('while') + #TODO: @lookat(tok.WHILE) def _lint(self, node): condition = node.kids[0] - if condition.kind == 'primary' and condition.opcode in ('false', 'null'): + if condition.kind == tok.PRIMARY and condition.opcode in (op.FALSE, op.NULL): return condition - @lookat('lc') + @lookat(tok.LC) def _lint(self, node): - if node.parent and node.parent.kind == 'lc': + if node.parent and node.parent.kind == tok.LC: return node class useless_void: 'use of the void type may be unnecessary (void is always undefined)' - @lookat('unaryop:void') + @lookat((tok.UNARYOP, op.VOID)) def _lint(self, node): return node class parseint_missing_radix: 'parseInt missing radix parameter' - @lookat('lp:call') + @lookat((tok.LP, op.CALL)) def _lint(self, node): - if node.kids[0].kind == 'name' and node.kids[0].atom == 'parseInt' and len(node.kids) <= 2: + if node.kids[0].kind == tok.NAME and node.kids[0].atom == 'parseInt' and len(node.kids) <= 2: return node class leading_decimal_point: 'leading decimal point may indicate a number or an object member' - @lookat('number') + @lookat(tok.NUMBER) def _lint(self, node): if node.atom.startswith('.'): return node class trailing_decimal_point: 'trailing decimal point may indicate a number or an object member' - @lookat('number') + @lookat(tok.NUMBER) def _lint(self, node): - if node.parent.kind == 'dot': + if node.parent.kind == tok.DOT: return node if node.atom.endswith('.'): return node @@ -402,14 +404,14 @@ class octal_number: 'leading zeros make an octal number' _regexp = re.compile('^0[0-9]') - @lookat('number') + @lookat(tok.NUMBER) def _line(self, node): if self._regexp.match(node.atom): return node class trailing_comma_in_array: 'extra comma is not recommended in array initializers' - @lookat('rb') + @lookat(tok.RB) def _line(self, node): if node.end_comma: return node Modified: trunk/pyspidermonkey/pyspidermonkey.c =================================================================== --- trunk/pyspidermonkey/pyspidermonkey.c 2008-03-01 17:32:55 UTC (rev 148) +++ trunk/pyspidermonkey/pyspidermonkey.c 2008-03-01 18:44:53 UTC (rev 149) @@ -41,7 +41,11 @@ }; JS_STATIC_ASSERT(ARRAY_COUNT(error_names) == JSErr_Limit); +/* Use different numeric ranges to avoid accidental confusion. */ +#define TOK_TO_NUM(tok) (tok+1000) +#define OPCODE_TO_NUM(op) (op+2000) + /** MODULE INITIALIZATION */ @@ -57,7 +61,45 @@ PyMODINIT_FUNC initpyspidermonkey() { - (void)Py_InitModule("pyspidermonkey", module_methods); + PyObject* module; + PyObject* class; + PyObject* tok; + PyObject* op; + int i; + + module = Py_InitModule("pyspidermonkey", module_methods); + if (!module) + return; + + class = PyClass_New(NULL, PyDict_New(), PyString_FromString("spidermonkey_constants")); + if (!class) + return; + + /* set up tokens */ + tok = PyInstance_New(class, NULL, NULL); + if (!tok) + return; + if (PyObject_SetAttrString(module, "tok", tok) == -1) + return; + for (i = 0; i < ARRAY_COUNT(tokens); i++) { + if (PyObject_SetAttrString(tok, tokens[i], PyLong_FromLong(TOK_TO_NUM(i))) == -1) + return; + } + + /* set up opcodes */ + op = PyInstance_New(class, NULL, NULL); + if (!op) + return; + if (PyObject_SetAttrString(module, "op", op) == -1) + return; + for (i = 0; i < ARRAY_COUNT(opcodes); i++) { + /* yank off the JSOP prefix */ + const char* opcode = opcodes[i]; + if (strlen(opcode) > 5) + opcode += 5; + if (PyObject_SetAttrString(op, opcode, PyLong_FromLong(OPCODE_TO_NUM(i))) == -1) + return; + } } PyMODINIT_FUNC @@ -131,7 +173,7 @@ PyTuple_SET_ITEM(tuple, node_offset, kw); - if (PyDict_SetItemString(kw, "type", PyString_FromString(tokens[jsnode->pn_type])) == -1) + if (PyDict_SetItemString(kw, "type", Py_BuildValue("i", TOK_TO_NUM(jsnode->pn_type))) == -1) goto fail; if (PyDict_SetItemString(kw, "node_index", Py_BuildValue("i", node_offset)) == -1) goto fail; @@ -153,7 +195,7 @@ goto fail; } - if (PyDict_SetItemString(kw, "opcode", PyString_FromString(opcodes[jsnode->pn_op])) == -1) + if (PyDict_SetItemString(kw, "opcode", Py_BuildValue("i", OPCODE_TO_NUM(jsnode->pn_op))) == -1) goto fail; if (jsnode->pn_type == TOK_NUMBER) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |