javascriptlint-commit Mailing List for JavaScript Lint (Page 10)
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...> - 2008-03-04 03:10:55
|
Revision: 162
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=162&view=rev
Author: matthiasmiller
Date: 2008-03-03 19:10:46 -0800 (Mon, 03 Mar 2008)
Log Message:
-----------
actually set the eol-style property
Modified Paths:
--------------
trunk/pyjsl/jsparse.py
trunk/pyjsl/util.py
Property Changed:
----------------
trunk/COPYING
trunk/DEVELOPMENT
trunk/INSTALL
trunk/jsl.py
trunk/pyjsl/__init__.py
trunk/pyjsl/conf.py
trunk/pyjsl/jsparse.py
trunk/pyjsl/lint.py
trunk/pyjsl/util.py
trunk/pyjsl/visitation.py
trunk/pyjsl/warnings.py
trunk/pyspidermonkey/pyspidermonkey.c
trunk/pyspidermonkey/tokens.tbl
trunk/setup.py
trunk/test.py
Property changes on: trunk/COPYING
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
Property changes on: trunk/DEVELOPMENT
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
Property changes on: trunk/INSTALL
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
Property changes on: trunk/jsl.py
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
Property changes on: trunk/pyjsl/__init__.py
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
Property changes on: trunk/pyjsl/conf.py
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
Modified: trunk/pyjsl/jsparse.py
===================================================================
--- trunk/pyjsl/jsparse.py 2008-03-04 01:34:39 UTC (rev 161)
+++ trunk/pyjsl/jsparse.py 2008-03-04 03:10:46 UTC (rev 162)
@@ -1,319 +1,319 @@
-#!/usr/bin/python
-""" Parses a script into nodes. """
-import bisect
-import re
-import unittest
-
-import pyspidermonkey
-from pyspidermonkey import tok, op
-
-_tok_names = dict(zip(
- [getattr(tok, prop) for prop in dir(tok)],
- ['tok.%s' % prop for prop in dir(tok)]
-))
-
-class NodePos():
- def __init__(self, line, col):
- self.line = line
- self.col = col
- def __cmp__(self, other):
- if self.line < other.line:
- return -1
- if self.line > other.line:
- return 1
- if self.col < other.col:
- return -1
- if self.col > other.col:
- return 1
- return 0
- def __str__(self):
- return '(line %i, col %i)' % (self.line+1, self.col+1)
-
-class NodePositions():
- " Given a string, allows [x] lookups for NodePos line and column numbers."
- def __init__(self, text):
- # Find the length of each line and incrementally sum all of the lengths
- # to determine the ending position of each line.
- self._lines = text.splitlines(True)
- lines = [0] + [len(x) for x in self._lines]
- for x in range(1, len(lines)):
- lines[x] += lines[x-1]
- self._line_offsets = lines
- def from_offset(self, offset):
- line = bisect.bisect(self._line_offsets, offset)-1
- col = offset - self._line_offsets[line]
- return NodePos(line, col)
- def to_offset(self, pos):
- offset = self._line_offsets[pos.line] + pos.col
- assert offset <= self._line_offsets[pos.line+1] # out-of-bounds col num
- return offset
- def text(self, start, end):
- assert start <= end
- # Trim the ending first in case it's a single line.
- lines = self._lines[start.line:end.line+1]
- lines[-1] = lines[-1][:end.col+1]
- lines[0] = lines[0][start.col:]
- return ''.join(lines)
-
-class NodeRanges():
- def __init__(self):
- self._offsets = []
- def add(self, start, end):
- i = bisect.bisect_left(self._offsets, start)
- if i % 2 == 1:
- i -= 1
- start = self._offsets[i]
-
- end = end + 1
- j = bisect.bisect_left(self._offsets, end)
- if j % 2 == 1:
- end = self._offsets[j]
- j += 1
-
- self._offsets[i:j] = [start,end]
- def has(self, pos):
- return bisect.bisect_right(self._offsets, pos) % 2 == 1
-
-class _Node():
- def add_child(self, node):
- if node:
- node.node_index = len(self.kids)
- node.parent = self
- self.kids.append(node)
-
- def start_pos(self):
- try:
- return self._start_pos
- except AttributeError:
- self._start_pos = NodePos(self._start_line, self._start_col)
- return self._start_pos
-
- def end_pos(self):
- try:
- return self._end_pos
- except AttributeError:
- self._end_pos = NodePos(self._end_line, self._end_col)
- return self._end_pos
-
- def __str__(self):
- kind = self.kind
- if not kind:
- kind = '(none)'
- return '%s>%s' % (_tok_names[kind], str(self.kids))
-
- def is_equivalent(self, other, are_functions_equiv=False):
- if not other:
- return False
-
- # Bail out for functions
- if not are_functions_equiv:
- if self.kind == tok.FUNCTION:
- return False
- if self.kind == tok.LP and self.opcode == op.CALL:
- return False
-
- if self.kind != other.kind:
- return False
- if self.opcode != other.opcode:
- return False
-
- # Check atoms on names, properties, and string constants
- if self.kind in (tok.NAME, tok.DOT, tok.STRING) and self.atom != other.atom:
- return False
-
- # Check values on numbers
- if self.kind == tok.NUMBER and self.dval != other.dval:
- return False
-
- # Compare child nodes
- if len(self.kids) != len(other.kids):
- return False
- for i in range(0, len(self.kids)):
- # Watch for dead nodes
- if not self.kids[i]:
- if not other.kids[i]: return True
- else: return False
- if not self.kids[i].is_equivalent(other.kids[i]):
- return False
-
- return True
-
-def _parse_comments(script, root, node_positions, ignore_ranges):
- pos = 0
- single_line_re = r"//[^\r\n]*"
- multi_line_re = r"/\*(.*?)\*/"
- full_re = "(%s)|(%s)" % (single_line_re, multi_line_re)
- comment_re = re.compile(full_re, re.DOTALL)
-
- comments = []
- while True:
- match = comment_re.search(script, pos)
- if not match:
- return comments
-
- # Get the comment text
- comment_text = script[match.start():match.end()]
- if comment_text.startswith('/*'):
- comment_text = comment_text[2:-2]
- opcode = 'JSOP_C_COMMENT'
- else:
- comment_text = comment_text[2:]
- opcode = 'JSOP_CPP_COMMENT'
- opcode = opcode[5:].lower()
-
- start_offset = match.start()+1
- end_offset = match.end()
-
- # Make sure it doesn't start in a string or regexp
- if not ignore_ranges.has(start_offset):
- start_pos = node_positions.from_offset(start_offset)
- end_pos = node_positions.from_offset(end_offset)
- kwargs = {
- 'type': 'COMMENT',
- 'atom': comment_text,
- 'opcode': opcode,
- '_start_line': start_pos.line,
- '_start_col': start_pos.col,
- '_end_line': end_pos.line,
- '_end_col': end_pos.col,
- 'parent': None,
- 'kids': [],
- 'node_index': None
- }
- comment_node = _Node()
- comment_node.__dict__.update(kwargs)
- comments.append(comment_node)
- pos = match.end()
- else:
- pos = match.start()+1
-
-def parse(script, error_callback):
- def _wrapped_callback(line, col, msg):
- assert msg.startswith('JSMSG_')
- msg = msg[6:].lower()
- error_callback(line, col, msg)
-
- positions = NodePositions(script)
-
- roots = []
- nodes = []
- comment_ignore_ranges = NodeRanges()
- def process(node):
- if node.kind == tok.NUMBER:
- node.atom = positions.text(node.start_pos(), node.end_pos())
- elif node.kind == tok.STRING or \
- (node.kind == tok.OBJECT and node.opcode == op.REGEXP):
- start_offset = positions.to_offset(node.start_pos())
- end_offset = positions.to_offset(node.end_pos())
- comment_ignore_ranges.add(start_offset, end_offset)
- for kid in node.kids:
- if kid:
- process(kid)
- def pop():
- nodes.pop()
-
- roots = pyspidermonkey.traverse(script, _Node, _wrapped_callback)
- assert len(roots) == 1
- root_node = roots[0]
- process(root_node)
-
- comments = _parse_comments(script, root_node, positions, comment_ignore_ranges)
- return root_node, comments
-
-def _dump_node(node, depth=0):
- print '. '*depth,
- if node is None:
- print '(none)'
- else:
- print '%s\t%s, %s' % (_tok_names[node.kind], node.start_pos(), node.end_pos())
- for node in node.kids:
- _dump_node(node, depth+1)
-
-def dump_tree(script):
- def error_callback(line, col, msg):
- print '(%i, %i): %s', (line, col, msg)
- node, comments = parse(script, error_callback)
- _dump_node(node)
-
-class TestComments(unittest.TestCase):
- def _test(self, script, expected_comments):
- root, comments = parse(script, lambda line, col, msg: None)
- encountered_comments = [node.atom for node in comments]
- self.assertEquals(encountered_comments, list(expected_comments))
- def testSimpleComments(self):
- self._test('re = /\//g', ())
- self._test('re = /\///g', ())
- self._test('re = /\////g', ('g',))
- def testCComments(self):
- self._test('/*a*//*b*/', ('a', 'b'))
- self._test('/*a\r\na*//*b\r\nb*/', ('a\r\na', 'b\r\nb'))
- self._test('a//*b*/c', ('*b*/c',))
- self._test('a///*b*/c', ('/*b*/c',))
- self._test('a/*//*/;', ('//',))
- self._test('a/*b*/+/*c*/d', ('b', 'c'))
-
-class TestNodePositions(unittest.TestCase):
- def _test(self, text, expected_lines, expected_cols):
- # Get a NodePos list
- positions = NodePositions(text)
- positions = [positions.from_offset(i) for i in range(0, len(text))]
- encountered_lines = ''.join([str(x.line) for x in positions])
- encountered_cols = ''.join([str(x.col) for x in positions])
- self.assertEquals(encountered_lines, expected_lines.replace(' ', ''))
- self.assertEquals(encountered_cols, expected_cols.replace(' ', ''))
- def testSimple(self):
- self._test(
- 'abc\r\ndef\nghi\n\nj',
- '0000 0 1111 2222 3 4',
- '0123 4 0123 0123 0 0'
- )
- self._test(
- '\rabc',
- '0 111',
- '0 012'
- )
- def testText(self):
- pos = NodePositions('abc\r\ndef\n\nghi')
- self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 0)), 'a')
- self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 2)), 'abc')
- self.assertEquals(pos.text(NodePos(0, 2), NodePos(1, 2)), 'c\r\ndef')
- def testOffset(self):
- pos = NodePositions('abc\r\ndef\n\nghi')
- self.assertEquals(pos.to_offset(NodePos(0, 2)), 2)
- self.assertEquals(pos.to_offset(NodePos(1, 0)), 5)
- self.assertEquals(pos.to_offset(NodePos(3, 1)), 11)
-
-class TestNodeRanges(unittest.TestCase):
- def testAdd(self):
- r = NodeRanges()
- r.add(5, 10)
- self.assertEquals(r._offsets, [5,11])
- r.add(15, 20)
- self.assertEquals(r._offsets, [5,11,15,21])
- r.add(21,22)
- self.assertEquals(r._offsets, [5,11,15,23])
- r.add(4,5)
- self.assertEquals(r._offsets, [4,11,15,23])
- r.add(9,11)
- self.assertEquals(r._offsets, [4,12,15,23])
- r.add(10,20)
- self.assertEquals(r._offsets, [4,23])
- r.add(4,22)
- self.assertEquals(r._offsets, [4,23])
- r.add(30,30)
- self.assertEquals(r._offsets, [4,23,30,31])
- def testHas(self):
- r = NodeRanges()
- r.add(5, 10)
- r.add(15, 15)
- assert not r.has(4)
- assert r.has(5)
- assert r.has(6)
- assert r.has(9)
- assert r.has(10)
- assert not r.has(14)
- assert r.has(15)
- assert not r.has(16)
-if __name__ == '__main__':
- unittest.main()
-
+#!/usr/bin/python
+""" Parses a script into nodes. """
+import bisect
+import re
+import unittest
+
+import pyspidermonkey
+from pyspidermonkey import tok, op
+
+_tok_names = dict(zip(
+ [getattr(tok, prop) for prop in dir(tok)],
+ ['tok.%s' % prop for prop in dir(tok)]
+))
+
+class NodePos():
+ def __init__(self, line, col):
+ self.line = line
+ self.col = col
+ def __cmp__(self, other):
+ if self.line < other.line:
+ return -1
+ if self.line > other.line:
+ return 1
+ if self.col < other.col:
+ return -1
+ if self.col > other.col:
+ return 1
+ return 0
+ def __str__(self):
+ return '(line %i, col %i)' % (self.line+1, self.col+1)
+
+class NodePositions():
+ " Given a string, allows [x] lookups for NodePos line and column numbers."
+ def __init__(self, text):
+ # Find the length of each line and incrementally sum all of the lengths
+ # to determine the ending position of each line.
+ self._lines = text.splitlines(True)
+ lines = [0] + [len(x) for x in self._lines]
+ for x in range(1, len(lines)):
+ lines[x] += lines[x-1]
+ self._line_offsets = lines
+ def from_offset(self, offset):
+ line = bisect.bisect(self._line_offsets, offset)-1
+ col = offset - self._line_offsets[line]
+ return NodePos(line, col)
+ def to_offset(self, pos):
+ offset = self._line_offsets[pos.line] + pos.col
+ assert offset <= self._line_offsets[pos.line+1] # out-of-bounds col num
+ return offset
+ def text(self, start, end):
+ assert start <= end
+ # Trim the ending first in case it's a single line.
+ lines = self._lines[start.line:end.line+1]
+ lines[-1] = lines[-1][:end.col+1]
+ lines[0] = lines[0][start.col:]
+ return ''.join(lines)
+
+class NodeRanges():
+ def __init__(self):
+ self._offsets = []
+ def add(self, start, end):
+ i = bisect.bisect_left(self._offsets, start)
+ if i % 2 == 1:
+ i -= 1
+ start = self._offsets[i]
+
+ end = end + 1
+ j = bisect.bisect_left(self._offsets, end)
+ if j % 2 == 1:
+ end = self._offsets[j]
+ j += 1
+
+ self._offsets[i:j] = [start,end]
+ def has(self, pos):
+ return bisect.bisect_right(self._offsets, pos) % 2 == 1
+
+class _Node():
+ def add_child(self, node):
+ if node:
+ node.node_index = len(self.kids)
+ node.parent = self
+ self.kids.append(node)
+
+ def start_pos(self):
+ try:
+ return self._start_pos
+ except AttributeError:
+ self._start_pos = NodePos(self._start_line, self._start_col)
+ return self._start_pos
+
+ def end_pos(self):
+ try:
+ return self._end_pos
+ except AttributeError:
+ self._end_pos = NodePos(self._end_line, self._end_col)
+ return self._end_pos
+
+ def __str__(self):
+ kind = self.kind
+ if not kind:
+ kind = '(none)'
+ return '%s>%s' % (_tok_names[kind], str(self.kids))
+
+ def is_equivalent(self, other, are_functions_equiv=False):
+ if not other:
+ return False
+
+ # Bail out for functions
+ if not are_functions_equiv:
+ if self.kind == tok.FUNCTION:
+ return False
+ if self.kind == tok.LP and self.opcode == op.CALL:
+ return False
+
+ if self.kind != other.kind:
+ return False
+ if self.opcode != other.opcode:
+ return False
+
+ # Check atoms on names, properties, and string constants
+ if self.kind in (tok.NAME, tok.DOT, tok.STRING) and self.atom != other.atom:
+ return False
+
+ # Check values on numbers
+ if self.kind == tok.NUMBER and self.dval != other.dval:
+ return False
+
+ # Compare child nodes
+ if len(self.kids) != len(other.kids):
+ return False
+ for i in range(0, len(self.kids)):
+ # Watch for dead nodes
+ if not self.kids[i]:
+ if not other.kids[i]: return True
+ else: return False
+ if not self.kids[i].is_equivalent(other.kids[i]):
+ return False
+
+ return True
+
+def _parse_comments(script, root, node_positions, ignore_ranges):
+ pos = 0
+ single_line_re = r"//[^\r\n]*"
+ multi_line_re = r"/\*(.*?)\*/"
+ full_re = "(%s)|(%s)" % (single_line_re, multi_line_re)
+ comment_re = re.compile(full_re, re.DOTALL)
+
+ comments = []
+ while True:
+ match = comment_re.search(script, pos)
+ if not match:
+ return comments
+
+ # Get the comment text
+ comment_text = script[match.start():match.end()]
+ if comment_text.startswith('/*'):
+ comment_text = comment_text[2:-2]
+ opcode = 'JSOP_C_COMMENT'
+ else:
+ comment_text = comment_text[2:]
+ opcode = 'JSOP_CPP_COMMENT'
+ opcode = opcode[5:].lower()
+
+ start_offset = match.start()+1
+ end_offset = match.end()
+
+ # Make sure it doesn't start in a string or regexp
+ if not ignore_ranges.has(start_offset):
+ start_pos = node_positions.from_offset(start_offset)
+ end_pos = node_positions.from_offset(end_offset)
+ kwargs = {
+ 'type': 'COMMENT',
+ 'atom': comment_text,
+ 'opcode': opcode,
+ '_start_line': start_pos.line,
+ '_start_col': start_pos.col,
+ '_end_line': end_pos.line,
+ '_end_col': end_pos.col,
+ 'parent': None,
+ 'kids': [],
+ 'node_index': None
+ }
+ comment_node = _Node()
+ comment_node.__dict__.update(kwargs)
+ comments.append(comment_node)
+ pos = match.end()
+ else:
+ pos = match.start()+1
+
+def parse(script, error_callback):
+ def _wrapped_callback(line, col, msg):
+ assert msg.startswith('JSMSG_')
+ msg = msg[6:].lower()
+ error_callback(line, col, msg)
+
+ positions = NodePositions(script)
+
+ roots = []
+ nodes = []
+ comment_ignore_ranges = NodeRanges()
+ def process(node):
+ if node.kind == tok.NUMBER:
+ node.atom = positions.text(node.start_pos(), node.end_pos())
+ elif node.kind == tok.STRING or \
+ (node.kind == tok.OBJECT and node.opcode == op.REGEXP):
+ start_offset = positions.to_offset(node.start_pos())
+ end_offset = positions.to_offset(node.end_pos())
+ comment_ignore_ranges.add(start_offset, end_offset)
+ for kid in node.kids:
+ if kid:
+ process(kid)
+ def pop():
+ nodes.pop()
+
+ roots = pyspidermonkey.traverse(script, _Node, _wrapped_callback)
+ assert len(roots) == 1
+ root_node = roots[0]
+ process(root_node)
+
+ comments = _parse_comments(script, root_node, positions, comment_ignore_ranges)
+ return root_node, comments
+
+def _dump_node(node, depth=0):
+ print '. '*depth,
+ if node is None:
+ print '(none)'
+ else:
+ print '%s\t%s, %s' % (_tok_names[node.kind], node.start_pos(), node.end_pos())
+ for node in node.kids:
+ _dump_node(node, depth+1)
+
+def dump_tree(script):
+ def error_callback(line, col, msg):
+ print '(%i, %i): %s', (line, col, msg)
+ node, comments = parse(script, error_callback)
+ _dump_node(node)
+
+class TestComments(unittest.TestCase):
+ def _test(self, script, expected_comments):
+ root, comments = parse(script, lambda line, col, msg: None)
+ encountered_comments = [node.atom for node in comments]
+ self.assertEquals(encountered_comments, list(expected_comments))
+ def testSimpleComments(self):
+ self._test('re = /\//g', ())
+ self._test('re = /\///g', ())
+ self._test('re = /\////g', ('g',))
+ def testCComments(self):
+ self._test('/*a*//*b*/', ('a', 'b'))
+ self._test('/*a\r\na*//*b\r\nb*/', ('a\r\na', 'b\r\nb'))
+ self._test('a//*b*/c', ('*b*/c',))
+ self._test('a///*b*/c', ('/*b*/c',))
+ self._test('a/*//*/;', ('//',))
+ self._test('a/*b*/+/*c*/d', ('b', 'c'))
+
+class TestNodePositions(unittest.TestCase):
+ def _test(self, text, expected_lines, expected_cols):
+ # Get a NodePos list
+ positions = NodePositions(text)
+ positions = [positions.from_offset(i) for i in range(0, len(text))]
+ encountered_lines = ''.join([str(x.line) for x in positions])
+ encountered_cols = ''.join([str(x.col) for x in positions])
+ self.assertEquals(encountered_lines, expected_lines.replace(' ', ''))
+ self.assertEquals(encountered_cols, expected_cols.replace(' ', ''))
+ def testSimple(self):
+ self._test(
+ 'abc\r\ndef\nghi\n\nj',
+ '0000 0 1111 2222 3 4',
+ '0123 4 0123 0123 0 0'
+ )
+ self._test(
+ '\rabc',
+ '0 111',
+ '0 012'
+ )
+ def testText(self):
+ pos = NodePositions('abc\r\ndef\n\nghi')
+ self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 0)), 'a')
+ self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 2)), 'abc')
+ self.assertEquals(pos.text(NodePos(0, 2), NodePos(1, 2)), 'c\r\ndef')
+ def testOffset(self):
+ pos = NodePositions('abc\r\ndef\n\nghi')
+ self.assertEquals(pos.to_offset(NodePos(0, 2)), 2)
+ self.assertEquals(pos.to_offset(NodePos(1, 0)), 5)
+ self.assertEquals(pos.to_offset(NodePos(3, 1)), 11)
+
+class TestNodeRanges(unittest.TestCase):
+ def testAdd(self):
+ r = NodeRanges()
+ r.add(5, 10)
+ self.assertEquals(r._offsets, [5,11])
+ r.add(15, 20)
+ self.assertEquals(r._offsets, [5,11,15,21])
+ r.add(21,22)
+ self.assertEquals(r._offsets, [5,11,15,23])
+ r.add(4,5)
+ self.assertEquals(r._offsets, [4,11,15,23])
+ r.add(9,11)
+ self.assertEquals(r._offsets, [4,12,15,23])
+ r.add(10,20)
+ self.assertEquals(r._offsets, [4,23])
+ r.add(4,22)
+ self.assertEquals(r._offsets, [4,23])
+ r.add(30,30)
+ self.assertEquals(r._offsets, [4,23,30,31])
+ def testHas(self):
+ r = NodeRanges()
+ r.add(5, 10)
+ r.add(15, 15)
+ assert not r.has(4)
+ assert r.has(5)
+ assert r.has(6)
+ assert r.has(9)
+ assert r.has(10)
+ assert not r.has(14)
+ assert r.has(15)
+ assert not r.has(16)
+if __name__ == '__main__':
+ unittest.main()
+
Property changes on: trunk/pyjsl/jsparse.py
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
Property changes on: trunk/pyjsl/lint.py
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
Modified: trunk/pyjsl/util.py
===================================================================
--- trunk/pyjsl/util.py 2008-03-04 01:34:39 UTC (rev 161)
+++ trunk/pyjsl/util.py 2008-03-04 03:10:46 UTC (rev 162)
@@ -1,16 +1,16 @@
-import codecs
-import os.path
-
-def readfile(path):
- file = codecs.open(path, 'r', 'utf-8')
- contents = file.read()
- if contents[0] == unicode(codecs.BOM_UTF8, 'utf8'):
- contents = contents[1:]
- return contents
-
-def normpath(path):
- path = os.path.abspath(path)
- path = os.path.normcase(path)
- path = os.path.normpath(path)
- return path
-
+import codecs
+import os.path
+
+def readfile(path):
+ file = codecs.open(path, 'r', 'utf-8')
+ contents = file.read()
+ if contents[0] == unicode(codecs.BOM_UTF8, 'utf8'):
+ contents = contents[1:]
+ return contents
+
+def normpath(path):
+ path = os.path.abspath(path)
+ path = os.path.normcase(path)
+ path = os.path.normpath(path)
+ return path
+
Property changes on: trunk/pyjsl/util.py
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
Property changes on: trunk/pyjsl/visitation.py
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
Property changes on: trunk/pyjsl/warnings.py
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
Property changes on: trunk/pyspidermonkey/pyspidermonkey.c
___________________________________________________________________
Name: eol-style
- native
Property changes on: trunk/pyspidermonkey/tokens.tbl
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
Property changes on: trunk/setup.py
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
Property changes on: trunk/test.py
___________________________________________________________________
Name: eol-style
- native
Name: svn:eol-style
+ native
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-04 01:34:41
|
Revision: 161
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=161&view=rev
Author: matthiasmiller
Date: 2008-03-03 17:34:39 -0800 (Mon, 03 Mar 2008)
Log Message:
-----------
rename pyjsl.parse to pyjsl.htmlparse
Modified Paths:
--------------
trunk/pyjsl/lint.py
Added Paths:
-----------
trunk/pyjsl/jsparse.py
Removed Paths:
-------------
trunk/pyjsl/parse.py
Copied: trunk/pyjsl/jsparse.py (from rev 157, trunk/pyjsl/parse.py)
===================================================================
--- trunk/pyjsl/jsparse.py (rev 0)
+++ trunk/pyjsl/jsparse.py 2008-03-04 01:34:39 UTC (rev 161)
@@ -0,0 +1,319 @@
+#!/usr/bin/python
+""" Parses a script into nodes. """
+import bisect
+import re
+import unittest
+
+import pyspidermonkey
+from pyspidermonkey import tok, op
+
+_tok_names = dict(zip(
+ [getattr(tok, prop) for prop in dir(tok)],
+ ['tok.%s' % prop for prop in dir(tok)]
+))
+
+class NodePos():
+ def __init__(self, line, col):
+ self.line = line
+ self.col = col
+ def __cmp__(self, other):
+ if self.line < other.line:
+ return -1
+ if self.line > other.line:
+ return 1
+ if self.col < other.col:
+ return -1
+ if self.col > other.col:
+ return 1
+ return 0
+ def __str__(self):
+ return '(line %i, col %i)' % (self.line+1, self.col+1)
+
+class NodePositions():
+ " Given a string, allows [x] lookups for NodePos line and column numbers."
+ def __init__(self, text):
+ # Find the length of each line and incrementally sum all of the lengths
+ # to determine the ending position of each line.
+ self._lines = text.splitlines(True)
+ lines = [0] + [len(x) for x in self._lines]
+ for x in range(1, len(lines)):
+ lines[x] += lines[x-1]
+ self._line_offsets = lines
+ def from_offset(self, offset):
+ line = bisect.bisect(self._line_offsets, offset)-1
+ col = offset - self._line_offsets[line]
+ return NodePos(line, col)
+ def to_offset(self, pos):
+ offset = self._line_offsets[pos.line] + pos.col
+ assert offset <= self._line_offsets[pos.line+1] # out-of-bounds col num
+ return offset
+ def text(self, start, end):
+ assert start <= end
+ # Trim the ending first in case it's a single line.
+ lines = self._lines[start.line:end.line+1]
+ lines[-1] = lines[-1][:end.col+1]
+ lines[0] = lines[0][start.col:]
+ return ''.join(lines)
+
+class NodeRanges():
+ def __init__(self):
+ self._offsets = []
+ def add(self, start, end):
+ i = bisect.bisect_left(self._offsets, start)
+ if i % 2 == 1:
+ i -= 1
+ start = self._offsets[i]
+
+ end = end + 1
+ j = bisect.bisect_left(self._offsets, end)
+ if j % 2 == 1:
+ end = self._offsets[j]
+ j += 1
+
+ self._offsets[i:j] = [start,end]
+ def has(self, pos):
+ return bisect.bisect_right(self._offsets, pos) % 2 == 1
+
+class _Node():
+ def add_child(self, node):
+ if node:
+ node.node_index = len(self.kids)
+ node.parent = self
+ self.kids.append(node)
+
+ def start_pos(self):
+ try:
+ return self._start_pos
+ except AttributeError:
+ self._start_pos = NodePos(self._start_line, self._start_col)
+ return self._start_pos
+
+ def end_pos(self):
+ try:
+ return self._end_pos
+ except AttributeError:
+ self._end_pos = NodePos(self._end_line, self._end_col)
+ return self._end_pos
+
+ def __str__(self):
+ kind = self.kind
+ if not kind:
+ kind = '(none)'
+ return '%s>%s' % (_tok_names[kind], str(self.kids))
+
+ def is_equivalent(self, other, are_functions_equiv=False):
+ if not other:
+ return False
+
+ # Bail out for functions
+ if not are_functions_equiv:
+ if self.kind == tok.FUNCTION:
+ return False
+ if self.kind == tok.LP and self.opcode == op.CALL:
+ return False
+
+ if self.kind != other.kind:
+ return False
+ if self.opcode != other.opcode:
+ return False
+
+ # Check atoms on names, properties, and string constants
+ if self.kind in (tok.NAME, tok.DOT, tok.STRING) and self.atom != other.atom:
+ return False
+
+ # Check values on numbers
+ if self.kind == tok.NUMBER and self.dval != other.dval:
+ return False
+
+ # Compare child nodes
+ if len(self.kids) != len(other.kids):
+ return False
+ for i in range(0, len(self.kids)):
+ # Watch for dead nodes
+ if not self.kids[i]:
+ if not other.kids[i]: return True
+ else: return False
+ if not self.kids[i].is_equivalent(other.kids[i]):
+ return False
+
+ return True
+
+def _parse_comments(script, root, node_positions, ignore_ranges):
+ pos = 0
+ single_line_re = r"//[^\r\n]*"
+ multi_line_re = r"/\*(.*?)\*/"
+ full_re = "(%s)|(%s)" % (single_line_re, multi_line_re)
+ comment_re = re.compile(full_re, re.DOTALL)
+
+ comments = []
+ while True:
+ match = comment_re.search(script, pos)
+ if not match:
+ return comments
+
+ # Get the comment text
+ comment_text = script[match.start():match.end()]
+ if comment_text.startswith('/*'):
+ comment_text = comment_text[2:-2]
+ opcode = 'JSOP_C_COMMENT'
+ else:
+ comment_text = comment_text[2:]
+ opcode = 'JSOP_CPP_COMMENT'
+ opcode = opcode[5:].lower()
+
+ start_offset = match.start()+1
+ end_offset = match.end()
+
+ # Make sure it doesn't start in a string or regexp
+ if not ignore_ranges.has(start_offset):
+ start_pos = node_positions.from_offset(start_offset)
+ end_pos = node_positions.from_offset(end_offset)
+ kwargs = {
+ 'type': 'COMMENT',
+ 'atom': comment_text,
+ 'opcode': opcode,
+ '_start_line': start_pos.line,
+ '_start_col': start_pos.col,
+ '_end_line': end_pos.line,
+ '_end_col': end_pos.col,
+ 'parent': None,
+ 'kids': [],
+ 'node_index': None
+ }
+ comment_node = _Node()
+ comment_node.__dict__.update(kwargs)
+ comments.append(comment_node)
+ pos = match.end()
+ else:
+ pos = match.start()+1
+
+def parse(script, error_callback):
+ def _wrapped_callback(line, col, msg):
+ assert msg.startswith('JSMSG_')
+ msg = msg[6:].lower()
+ error_callback(line, col, msg)
+
+ positions = NodePositions(script)
+
+ roots = []
+ nodes = []
+ comment_ignore_ranges = NodeRanges()
+ def process(node):
+ if node.kind == tok.NUMBER:
+ node.atom = positions.text(node.start_pos(), node.end_pos())
+ elif node.kind == tok.STRING or \
+ (node.kind == tok.OBJECT and node.opcode == op.REGEXP):
+ start_offset = positions.to_offset(node.start_pos())
+ end_offset = positions.to_offset(node.end_pos())
+ comment_ignore_ranges.add(start_offset, end_offset)
+ for kid in node.kids:
+ if kid:
+ process(kid)
+ def pop():
+ nodes.pop()
+
+ roots = pyspidermonkey.traverse(script, _Node, _wrapped_callback)
+ assert len(roots) == 1
+ root_node = roots[0]
+ process(root_node)
+
+ comments = _parse_comments(script, root_node, positions, comment_ignore_ranges)
+ return root_node, comments
+
+def _dump_node(node, depth=0):
+ print '. '*depth,
+ if node is None:
+ print '(none)'
+ else:
+ print '%s\t%s, %s' % (_tok_names[node.kind], node.start_pos(), node.end_pos())
+ for node in node.kids:
+ _dump_node(node, depth+1)
+
+def dump_tree(script):
+ def error_callback(line, col, msg):
+ print '(%i, %i): %s', (line, col, msg)
+ node, comments = parse(script, error_callback)
+ _dump_node(node)
+
+class TestComments(unittest.TestCase):
+ def _test(self, script, expected_comments):
+ root, comments = parse(script, lambda line, col, msg: None)
+ encountered_comments = [node.atom for node in comments]
+ self.assertEquals(encountered_comments, list(expected_comments))
+ def testSimpleComments(self):
+ self._test('re = /\//g', ())
+ self._test('re = /\///g', ())
+ self._test('re = /\////g', ('g',))
+ def testCComments(self):
+ self._test('/*a*//*b*/', ('a', 'b'))
+ self._test('/*a\r\na*//*b\r\nb*/', ('a\r\na', 'b\r\nb'))
+ self._test('a//*b*/c', ('*b*/c',))
+ self._test('a///*b*/c', ('/*b*/c',))
+ self._test('a/*//*/;', ('//',))
+ self._test('a/*b*/+/*c*/d', ('b', 'c'))
+
+class TestNodePositions(unittest.TestCase):
+ def _test(self, text, expected_lines, expected_cols):
+ # Get a NodePos list
+ positions = NodePositions(text)
+ positions = [positions.from_offset(i) for i in range(0, len(text))]
+ encountered_lines = ''.join([str(x.line) for x in positions])
+ encountered_cols = ''.join([str(x.col) for x in positions])
+ self.assertEquals(encountered_lines, expected_lines.replace(' ', ''))
+ self.assertEquals(encountered_cols, expected_cols.replace(' ', ''))
+ def testSimple(self):
+ self._test(
+ 'abc\r\ndef\nghi\n\nj',
+ '0000 0 1111 2222 3 4',
+ '0123 4 0123 0123 0 0'
+ )
+ self._test(
+ '\rabc',
+ '0 111',
+ '0 012'
+ )
+ def testText(self):
+ pos = NodePositions('abc\r\ndef\n\nghi')
+ self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 0)), 'a')
+ self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 2)), 'abc')
+ self.assertEquals(pos.text(NodePos(0, 2), NodePos(1, 2)), 'c\r\ndef')
+ def testOffset(self):
+ pos = NodePositions('abc\r\ndef\n\nghi')
+ self.assertEquals(pos.to_offset(NodePos(0, 2)), 2)
+ self.assertEquals(pos.to_offset(NodePos(1, 0)), 5)
+ self.assertEquals(pos.to_offset(NodePos(3, 1)), 11)
+
+class TestNodeRanges(unittest.TestCase):
+ def testAdd(self):
+ r = NodeRanges()
+ r.add(5, 10)
+ self.assertEquals(r._offsets, [5,11])
+ r.add(15, 20)
+ self.assertEquals(r._offsets, [5,11,15,21])
+ r.add(21,22)
+ self.assertEquals(r._offsets, [5,11,15,23])
+ r.add(4,5)
+ self.assertEquals(r._offsets, [4,11,15,23])
+ r.add(9,11)
+ self.assertEquals(r._offsets, [4,12,15,23])
+ r.add(10,20)
+ self.assertEquals(r._offsets, [4,23])
+ r.add(4,22)
+ self.assertEquals(r._offsets, [4,23])
+ r.add(30,30)
+ self.assertEquals(r._offsets, [4,23,30,31])
+ def testHas(self):
+ r = NodeRanges()
+ r.add(5, 10)
+ r.add(15, 15)
+ assert not r.has(4)
+ assert r.has(5)
+ assert r.has(6)
+ assert r.has(9)
+ assert r.has(10)
+ assert not r.has(14)
+ assert r.has(15)
+ assert not r.has(16)
+if __name__ == '__main__':
+ unittest.main()
+
Modified: trunk/pyjsl/lint.py
===================================================================
--- trunk/pyjsl/lint.py 2008-03-03 22:53:12 UTC (rev 160)
+++ trunk/pyjsl/lint.py 2008-03-04 01:34:39 UTC (rev 161)
@@ -3,7 +3,7 @@
import re
import conf
-import parse
+import jsparse
import visitation
import warnings
import util
@@ -149,7 +149,7 @@
def _lint_script(script, script_cache, lint_error, conf, import_callback):
def parse_error(row, col, msg):
if not msg in ('redeclared_var', 'var_hides_arg'):
- parse_errors.append((parse.NodePos(row, col), msg))
+ parse_errors.append((jsparse.NodePos(row, col), msg))
def report(node, errname):
_report(node.start_pos(), errname, True)
@@ -169,7 +169,7 @@
return lint_error(pos.line, pos.col, errname)
parse_errors = []
- root, comments = parse.parse(script, parse_error)
+ root, comments = jsparse.parse(script, parse_error)
ignores = []
start_ignore = None
declares = []
Deleted: trunk/pyjsl/parse.py
===================================================================
--- trunk/pyjsl/parse.py 2008-03-03 22:53:12 UTC (rev 160)
+++ trunk/pyjsl/parse.py 2008-03-04 01:34:39 UTC (rev 161)
@@ -1,321 +0,0 @@
-#!/usr/bin/python
-""" Parses a script into nodes. """
-import bisect
-import re
-import unittest
-
-import pyspidermonkey
-from pyspidermonkey import tok, op
-
-_tok_names = dict(zip(
- [getattr(tok, prop) for prop in dir(tok)],
- ['tok.%s' % prop for prop in dir(tok)]
-))
-_op_names = dict(zip(
- [getattr(op, prop) for prop in dir(op)],
- ['op.%s' % prop for prop in dir(op)]
-))
-
-class NodePos():
- def __init__(self, line, col):
- self.line = line
- self.col = col
- def __cmp__(self, other):
- if self.line < other.line:
- return -1
- if self.line > other.line:
- return 1
- if self.col < other.col:
- return -1
- if self.col > other.col:
- return 1
- return 0
- def __str__(self):
- return '(line %i, col %i)' % (self.line+1, self.col+1)
-
-class NodePositions():
- " Given a string, allows [x] lookups for NodePos line and column numbers."
- def __init__(self, text):
- # Find the length of each line and incrementally sum all of the lengths
- # to determine the ending position of each line.
- self._lines = text.splitlines(True)
- lines = [0] + [len(x) for x in self._lines]
- for x in range(1, len(lines)):
- lines[x] += lines[x-1]
- self._line_offsets = lines
- def from_offset(self, offset):
- line = bisect.bisect(self._line_offsets, offset)-1
- col = offset - self._line_offsets[line]
- return NodePos(line, col)
- def to_offset(self, pos):
- offset = self._line_offsets[pos.line] + pos.col
- assert offset <= self._line_offsets[pos.line+1] # out-of-bounds col num
- return offset
- def text(self, start, end):
- assert start <= end
- # Trim the ending first in case it's a single line.
- lines = self._lines[start.line:end.line+1]
- lines[-1] = lines[-1][:end.col+1]
- lines[0] = lines[0][start.col:]
- return ''.join(lines)
-
-class NodeRanges():
- def __init__(self):
- self._offsets = []
- def add(self, start, end):
- i = bisect.bisect_left(self._offsets, start)
- if i % 2 == 1:
- i -= 1
- start = self._offsets[i]
-
- end = end + 1
- j = bisect.bisect_left(self._offsets, end)
- if j % 2 == 1:
- end = self._offsets[j]
- j += 1
-
- self._offsets[i:j] = [start,end]
- def has(self, pos):
- return bisect.bisect_right(self._offsets, pos) % 2 == 1
-
-class _Node():
- def add_child(self, node):
- if node:
- node.node_index = len(self.kids)
- node.parent = self
- self.kids.append(node)
-
- def start_pos(self):
- try:
- return self._start_pos
- except AttributeError:
- self._start_pos = NodePos(self._start_line, self._start_col)
- return self._start_pos
-
- def end_pos(self):
- try:
- return self._end_pos
- except AttributeError:
- self._end_pos = NodePos(self._end_line, self._end_col)
- return self._end_pos
-
- def __str__(self):
- kind = self.kind
- if not kind:
- kind = '(none)'
- return '%s>%s' % (_tok_names[kind], str(self.kids))
-
- def is_equivalent(self, other, are_functions_equiv=False):
- if not other:
- return False
-
- # Bail out for functions
- if not are_functions_equiv:
- if self.kind == tok.FUNCTION:
- return False
- if self.kind == tok.LP and self.opcode == op.CALL:
- return False
-
- if self.kind != other.kind:
- return False
- if self.opcode != other.opcode:
- return False
-
- # Check atoms on names, properties, and string constants
- if self.kind in (tok.NAME, tok.DOT, tok.STRING) and self.atom != other.atom:
- return False
-
- # Check values on numbers
- if self.kind == tok.NUMBER and self.dval != other.dval:
- return False
-
- # Compare child nodes
- if len(self.kids) != len(other.kids):
- return False
- for i in range(0, len(self.kids)):
- # Watch for dead nodes
- if not self.kids[i]:
- if not other.kids[i]: return True
- else: return False
- if not self.kids[i].is_equivalent(other.kids[i]):
- return False
-
- return True
-
-def _parse_comments(script, root, node_positions, ignore_ranges):
- pos = 0
- single_line_re = r"//[^\r\n]*"
- multi_line_re = r"/\*(.*?)\*/"
- full_re = "(%s)|(%s)" % (single_line_re, multi_line_re)
- comment_re = re.compile(full_re, re.DOTALL)
-
- comments = []
- while True:
- match = comment_re.search(script, pos)
- if not match:
- return comments
-
- # Get the comment text
- comment_text = script[match.start():match.end()]
- if comment_text.startswith('/*'):
- comment_text = comment_text[2:-2]
- opcode = 'JSOP_C_COMMENT'
- else:
- comment_text = comment_text[2:]
- opcode = 'JSOP_CPP_COMMENT'
- opcode = opcode[5:].lower()
-
- start_offset = match.start()+1
- end_offset = match.end()
-
- # Make sure it doesn't start in a string or regexp
- if not ignore_ranges.has(start_offset):
- start_pos = node_positions.from_offset(start_offset)
- end_pos = node_positions.from_offset(end_offset)
- kwargs = {
- 'type': 'COMMENT',
- 'atom': comment_text,
- 'opcode': opcode,
- '_start_line': start_pos.line,
- '_start_col': start_pos.col,
- '_end_line': end_pos.line,
- '_end_col': end_pos.col,
- 'parent': None,
- 'kids': [],
- 'node_index': None
- }
- comment_node = _Node()
- comment_node.__dict__.update(kwargs)
- comments.append(comment_node)
- pos = match.end()
- else:
- pos = match.start()+1
-
-def parse(script, error_callback):
- def _wrapped_callback(line, col, msg):
- assert msg.startswith('JSMSG_')
- msg = msg[6:].lower()
- error_callback(line, col, msg)
-
- positions = NodePositions(script)
-
- roots = []
- nodes = []
- comment_ignore_ranges = NodeRanges()
- def process(node):
- if node.kind == tok.NUMBER:
- node.atom = positions.text(node.start_pos(), node.end_pos())
- elif node.kind == tok.STRING or \
- (node.kind == tok.OBJECT and node.opcode == op.REGEXP):
- start_offset = positions.to_offset(node.start_pos())
- end_offset = positions.to_offset(node.end_pos())
- comment_ignore_ranges.add(start_offset, end_offset)
- for kid in node.kids:
- if kid:
- process(kid)
-
- roots = pyspidermonkey.traverse(script, _Node, _wrapped_callback)
- assert len(roots) == 1
- root_node = roots[0]
- process(root_node)
-
- comments = _parse_comments(script, root_node, positions, comment_ignore_ranges)
- return root_node, comments
-
-def _dump_node(node, depth=0):
- print '. '*depth,
- if node is None:
- print '(none)'
- else:
- print '%s, %s\tfrom %s to %s' % (_tok_names[node.kind], _op_names[node.opcode], node.start_pos(), node.end_pos())
- for node in node.kids:
- _dump_node(node, depth+1)
-
-def dump_tree(script):
- def error_callback(line, col, msg):
- print '(%i, %i): %s', (line, col, msg)
- node, comments = parse(script, error_callback)
- _dump_node(node)
-
-class TestComments(unittest.TestCase):
- def _test(self, script, expected_comments):
- root, comments = parse(script, lambda line, col, msg: None)
- encountered_comments = [node.atom for node in comments]
- self.assertEquals(encountered_comments, list(expected_comments))
- def testSimpleComments(self):
- self._test('re = /\//g', ())
- self._test('re = /\///g', ())
- self._test('re = /\////g', ('g',))
- def testCComments(self):
- self._test('/*a*//*b*/', ('a', 'b'))
- self._test('/*a\r\na*//*b\r\nb*/', ('a\r\na', 'b\r\nb'))
- self._test('a//*b*/c', ('*b*/c',))
- self._test('a///*b*/c', ('/*b*/c',))
- self._test('a/*//*/;', ('//',))
- self._test('a/*b*/+/*c*/d', ('b', 'c'))
-
-class TestNodePositions(unittest.TestCase):
- def _test(self, text, expected_lines, expected_cols):
- # Get a NodePos list
- positions = NodePositions(text)
- positions = [positions.from_offset(i) for i in range(0, len(text))]
- encountered_lines = ''.join([str(x.line) for x in positions])
- encountered_cols = ''.join([str(x.col) for x in positions])
- self.assertEquals(encountered_lines, expected_lines.replace(' ', ''))
- self.assertEquals(encountered_cols, expected_cols.replace(' ', ''))
- def testSimple(self):
- self._test(
- 'abc\r\ndef\nghi\n\nj',
- '0000 0 1111 2222 3 4',
- '0123 4 0123 0123 0 0'
- )
- self._test(
- '\rabc',
- '0 111',
- '0 012'
- )
- def testText(self):
- pos = NodePositions('abc\r\ndef\n\nghi')
- self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 0)), 'a')
- self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 2)), 'abc')
- self.assertEquals(pos.text(NodePos(0, 2), NodePos(1, 2)), 'c\r\ndef')
- def testOffset(self):
- pos = NodePositions('abc\r\ndef\n\nghi')
- self.assertEquals(pos.to_offset(NodePos(0, 2)), 2)
- self.assertEquals(pos.to_offset(NodePos(1, 0)), 5)
- self.assertEquals(pos.to_offset(NodePos(3, 1)), 11)
-
-class TestNodeRanges(unittest.TestCase):
- def testAdd(self):
- r = NodeRanges()
- r.add(5, 10)
- self.assertEquals(r._offsets, [5,11])
- r.add(15, 20)
- self.assertEquals(r._offsets, [5,11,15,21])
- r.add(21,22)
- self.assertEquals(r._offsets, [5,11,15,23])
- r.add(4,5)
- self.assertEquals(r._offsets, [4,11,15,23])
- r.add(9,11)
- self.assertEquals(r._offsets, [4,12,15,23])
- r.add(10,20)
- self.assertEquals(r._offsets, [4,23])
- r.add(4,22)
- self.assertEquals(r._offsets, [4,23])
- r.add(30,30)
- self.assertEquals(r._offsets, [4,23,30,31])
- def testHas(self):
- r = NodeRanges()
- r.add(5, 10)
- r.add(15, 15)
- assert not r.has(4)
- assert r.has(5)
- assert r.has(6)
- assert r.has(9)
- assert r.has(10)
- assert not r.has(14)
- assert r.has(15)
- assert not r.has(16)
-if __name__ == '__main__':
- unittest.main()
-
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-03 22:53:16
|
Revision: 160
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=160&view=rev
Author: matthiasmiller
Date: 2008-03-03 14:53:12 -0800 (Mon, 03 Mar 2008)
Log Message:
-----------
change --dump to output opcodes
Modified Paths:
--------------
trunk/pyjsl/parse.py
Modified: trunk/pyjsl/parse.py
===================================================================
--- trunk/pyjsl/parse.py 2008-03-03 22:49:59 UTC (rev 159)
+++ trunk/pyjsl/parse.py 2008-03-03 22:53:12 UTC (rev 160)
@@ -11,6 +11,10 @@
[getattr(tok, prop) for prop in dir(tok)],
['tok.%s' % prop for prop in dir(tok)]
))
+_op_names = dict(zip(
+ [getattr(op, prop) for prop in dir(op)],
+ ['op.%s' % prop for prop in dir(op)]
+))
class NodePos():
def __init__(self, line, col):
@@ -223,7 +227,7 @@
if node is None:
print '(none)'
else:
- print '%s\t%s, %s' % (_tok_names[node.kind], node.start_pos(), node.end_pos())
+ print '%s, %s\tfrom %s to %s' % (_tok_names[node.kind], _op_names[node.opcode], node.start_pos(), node.end_pos())
for node in node.kids:
_dump_node(node, depth+1)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-03 22:50:06
|
Revision: 159
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=159&view=rev
Author: matthiasmiller
Date: 2008-03-03 14:49:59 -0800 (Mon, 03 Mar 2008)
Log Message:
-----------
remove obsolete code
Modified Paths:
--------------
trunk/pyjsl/parse.py
Modified: trunk/pyjsl/parse.py
===================================================================
--- trunk/pyjsl/parse.py 2008-03-03 22:46:15 UTC (rev 158)
+++ trunk/pyjsl/parse.py 2008-03-03 22:49:59 UTC (rev 159)
@@ -209,8 +209,6 @@
for kid in node.kids:
if kid:
process(kid)
- def pop():
- nodes.pop()
roots = pyspidermonkey.traverse(script, _Node, _wrapped_callback)
assert len(roots) == 1
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-03 22:46:17
|
Revision: 158
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=158&view=rev
Author: matthiasmiller
Date: 2008-03-03 14:46:15 -0800 (Mon, 03 Mar 2008)
Log Message:
-----------
pyspidermonkey.c: rename kw to the more descriptive pynode
Modified Paths:
--------------
trunk/pyspidermonkey/pyspidermonkey.c
Modified: trunk/pyspidermonkey/pyspidermonkey.c
===================================================================
--- trunk/pyspidermonkey/pyspidermonkey.c 2008-03-03 22:43:57 UTC (rev 157)
+++ trunk/pyspidermonkey/pyspidermonkey.c 2008-03-03 22:46:15 UTC (rev 158)
@@ -157,7 +157,7 @@
static int
traverse_node(JSContext* context, JSParseNode* jsnode, PyObject* parent, PyObject* tuple, int node_offset) {
JSContextData* data = JS_GetContextPrivate(context);
- PyObject* kw = NULL;
+ PyObject* pynode = NULL;
PyObject* kids = NULL;
/* TODO: make sure no tuple item already exists */
@@ -169,42 +169,42 @@
}
/* pass in a dictionary of options */
- kw = PyInstance_New(data->node_class, NULL, NULL);
- if (!kw)
+ pynode = PyInstance_New(data->node_class, NULL, NULL);
+ if (!pynode)
goto fail;
- PyTuple_SET_ITEM(tuple, node_offset, kw);
+ PyTuple_SET_ITEM(tuple, node_offset, pynode);
Py_INCREF(parent);
- if (PyObject_SetAttrString(kw, "parent", parent) == -1)
+ if (PyObject_SetAttrString(pynode, "parent", parent) == -1)
goto fail;
- if (PyObject_SetAttrString(kw, "kind", Py_BuildValue("i", TOK_TO_NUM(jsnode->pn_type))) == -1)
+ if (PyObject_SetAttrString(pynode, "kind", Py_BuildValue("i", TOK_TO_NUM(jsnode->pn_type))) == -1)
goto fail;
- if (PyObject_SetAttrString(kw, "node_index", Py_BuildValue("i", node_offset)) == -1)
+ if (PyObject_SetAttrString(pynode, "node_index", Py_BuildValue("i", node_offset)) == -1)
goto fail;
/* pass the position */
- if (PyObject_SetAttrString(kw, "_start_line", Py_BuildValue("i", jsnode->pn_pos.begin.lineno-1)) == -1)
+ if (PyObject_SetAttrString(pynode, "_start_line", Py_BuildValue("i", jsnode->pn_pos.begin.lineno-1)) == -1)
goto fail;
- if (PyObject_SetAttrString(kw, "_start_col", Py_BuildValue("i", jsnode->pn_pos.begin.index)) == -1)
+ if (PyObject_SetAttrString(pynode, "_start_col", Py_BuildValue("i", jsnode->pn_pos.begin.index)) == -1)
goto fail;
- if (PyObject_SetAttrString(kw, "_end_line", Py_BuildValue("i", jsnode->pn_pos.end.lineno-1)) == -1)
+ if (PyObject_SetAttrString(pynode, "_end_line", Py_BuildValue("i", jsnode->pn_pos.end.lineno-1)) == -1)
goto fail;
- if (PyObject_SetAttrString(kw, "_end_col", Py_BuildValue("i", jsnode->pn_pos.end.index)) == -1)
+ if (PyObject_SetAttrString(pynode, "_end_col", Py_BuildValue("i", jsnode->pn_pos.end.index)) == -1)
goto fail;
if ((jsnode->pn_type == TOK_NAME || jsnode->pn_type == TOK_DOT ||
jsnode->pn_type == TOK_STRING) && ATOM_IS_STRING(jsnode->pn_atom)) {
/* Convert the atom to a string. */
- if (PyObject_SetAttrString(kw, "atom", atom_to_string(jsnode->pn_atom)) == -1)
+ if (PyObject_SetAttrString(pynode, "atom", atom_to_string(jsnode->pn_atom)) == -1)
goto fail;
}
- if (PyObject_SetAttrString(kw, "opcode", Py_BuildValue("i", OPCODE_TO_NUM(jsnode->pn_op))) == -1)
+ if (PyObject_SetAttrString(pynode, "opcode", Py_BuildValue("i", OPCODE_TO_NUM(jsnode->pn_op))) == -1)
goto fail;
if (jsnode->pn_type == TOK_NUMBER) {
- if (PyObject_SetAttrString(kw, "dval", Py_BuildValue("d", jsnode->pn_dval)) == -1)
+ if (PyObject_SetAttrString(pynode, "dval", Py_BuildValue("d", jsnode->pn_dval)) == -1)
goto fail;
}
@@ -226,7 +226,7 @@
Py_INCREF(Py_None);
fn_name = Py_None;
}
- if (PyObject_SetAttrString(kw, "fn_name", fn_name) == -1)
+ if (PyObject_SetAttrString(pynode, "fn_name", fn_name) == -1)
goto fail;
/* get the function arguments */
@@ -256,19 +256,19 @@
name = atom_to_string(JSID_TO_ATOM(scope_property->id));
PyTuple_SET_ITEM(fn_args, (uint16)scope_property->shortid, name);
}
- if (PyObject_SetAttrString(kw, "fn_args", fn_args) == -1)
+ if (PyObject_SetAttrString(pynode, "fn_args", fn_args) == -1)
goto fail;
}
else if (jsnode->pn_type == TOK_RB) {
PyObject* end_comma = PyBool_FromLong(jsnode->pn_extra & PNX_ENDCOMMA);
- if (PyObject_SetAttrString(kw, "end_comma", end_comma) == -1)
+ if (PyObject_SetAttrString(pynode, "end_comma", end_comma) == -1)
goto fail;
}
switch (jsnode->pn_arity) {
case PN_FUNC:
kids = PyTuple_New(1);
- if (traverse_node(context, jsnode->pn_body, kw, kids, 0) == -1)
+ if (traverse_node(context, jsnode->pn_body, pynode, kids, 0) == -1)
return -1;
break;
@@ -277,7 +277,7 @@
int i;
kids = PyTuple_New(jsnode->pn_count);
for (i = 0, p = jsnode->pn_head; p; p = p->pn_next, i++) {
- if (traverse_node(context, p, kw, kids, i) == -1)
+ if (traverse_node(context, p, pynode, kids, i) == -1)
return -1;
}
}
@@ -285,31 +285,31 @@
case PN_TERNARY:
kids = PyTuple_New(3);
- if (traverse_node(context, jsnode->pn_kid1, kw, kids, 0) == -1)
+ if (traverse_node(context, jsnode->pn_kid1, pynode, kids, 0) == -1)
return -1;
- if (traverse_node(context, jsnode->pn_kid2, kw, kids, 1) == -1)
+ if (traverse_node(context, jsnode->pn_kid2, pynode, kids, 1) == -1)
return -1;
- if (traverse_node(context, jsnode->pn_kid3, kw, kids, 2) == -1)
+ if (traverse_node(context, jsnode->pn_kid3, pynode, kids, 2) == -1)
return -1;
break;
case PN_BINARY:
kids = PyTuple_New(2);
- if (traverse_node(context, jsnode->pn_left, kw, kids, 0) == -1)
+ if (traverse_node(context, jsnode->pn_left, pynode, kids, 0) == -1)
return -1;
- if (traverse_node(context, jsnode->pn_right, kw, kids, 1) == -1)
+ if (traverse_node(context, jsnode->pn_right, pynode, kids, 1) == -1)
return -1;
break;
case PN_UNARY:
kids = PyTuple_New(1);
- if (traverse_node(context, jsnode->pn_kid, kw, kids, 0) == -1)
+ if (traverse_node(context, jsnode->pn_kid, pynode, kids, 0) == -1)
return -1;
break;
case PN_NAME:
kids = PyTuple_New(1);
- if (traverse_node(context, jsnode->pn_expr, kw, kids, 0) == -1)
+ if (traverse_node(context, jsnode->pn_expr, pynode, kids, 0) == -1)
return -1;
break;
@@ -318,14 +318,14 @@
break;
}
- if (PyObject_SetAttrString(kw, "kids", kids) == -1)
+ if (PyObject_SetAttrString(pynode, "kids", kids) == -1)
goto fail;
return 0;
fail:
- if (kw) {
- Py_XDECREF(kw);
+ if (pynode) {
+ Py_XDECREF(pynode);
}
return -1;
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-03 22:43:59
|
Revision: 157
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=157&view=rev
Author: matthiasmiller
Date: 2008-03-03 14:43:57 -0800 (Mon, 03 Mar 2008)
Log Message:
-----------
change the c module to instantiate the Node objects and set the node's attributes to speed up parsing
Modified Paths:
--------------
trunk/pyjsl/parse.py
trunk/pyspidermonkey/pyspidermonkey.c
Modified: trunk/pyjsl/parse.py
===================================================================
--- trunk/pyjsl/parse.py 2008-03-03 18:41:11 UTC (rev 156)
+++ trunk/pyjsl/parse.py 2008-03-03 22:43:57 UTC (rev 157)
@@ -75,13 +75,6 @@
return bisect.bisect_right(self._offsets, pos) % 2 == 1
class _Node():
- def __init__(self, kids, parent=None, **kwargs):
- _to_node = lambda kid: kid and _Node(parent=self, **kid)
- self.__dict__.update(kwargs)
- self.args = kwargs
- self.parent = parent
- self.kids = map(_to_node, kids)
-
def add_child(self, node):
if node:
node.node_index = len(self.kids)
@@ -187,7 +180,8 @@
'kids': [],
'node_index': None
}
- comment_node = _Node(**kwargs)
+ comment_node = _Node()
+ comment_node.__dict__.update(kwargs)
comments.append(comment_node)
pos = match.end()
else:
@@ -218,9 +212,9 @@
def pop():
nodes.pop()
- roots = pyspidermonkey.traverse(script, _wrapped_callback)
+ roots = pyspidermonkey.traverse(script, _Node, _wrapped_callback)
assert len(roots) == 1
- root_node = _Node(**roots[0])
+ root_node = roots[0]
process(root_node)
comments = _parse_comments(script, root_node, positions, comment_ignore_ranges)
@@ -231,7 +225,7 @@
if node is None:
print '(none)'
else:
- print _tok_names[node.kind], '\t', node.args
+ print '%s\t%s, %s' % (_tok_names[node.kind], node.start_pos(), node.end_pos())
for node in node.kids:
_dump_node(node, depth+1)
Modified: trunk/pyspidermonkey/pyspidermonkey.c
===================================================================
--- trunk/pyspidermonkey/pyspidermonkey.c 2008-03-03 18:41:11 UTC (rev 156)
+++ trunk/pyspidermonkey/pyspidermonkey.c 2008-03-03 22:43:57 UTC (rev 157)
@@ -112,6 +112,7 @@
*/
typedef struct JSContextData {
+ PyObject* node_class;
PyObject* error_callback;
} JSContextData;
@@ -154,7 +155,8 @@
/* returns 0 on success and -1 on failure */
static int
-traverse_node(JSContext* context, JSParseNode* jsnode, PyObject* tuple, int node_offset) {
+traverse_node(JSContext* context, JSParseNode* jsnode, PyObject* parent, PyObject* tuple, int node_offset) {
+ JSContextData* data = JS_GetContextPrivate(context);
PyObject* kw = NULL;
PyObject* kids = NULL;
@@ -167,39 +169,42 @@
}
/* pass in a dictionary of options */
- kw = PyDict_New();
+ kw = PyInstance_New(data->node_class, NULL, NULL);
if (!kw)
goto fail;
PyTuple_SET_ITEM(tuple, node_offset, kw);
- if (PyDict_SetItemString(kw, "kind", Py_BuildValue("i", TOK_TO_NUM(jsnode->pn_type))) == -1)
+ Py_INCREF(parent);
+ if (PyObject_SetAttrString(kw, "parent", parent) == -1)
goto fail;
- if (PyDict_SetItemString(kw, "node_index", Py_BuildValue("i", node_offset)) == -1)
+ if (PyObject_SetAttrString(kw, "kind", Py_BuildValue("i", TOK_TO_NUM(jsnode->pn_type))) == -1)
goto fail;
+ if (PyObject_SetAttrString(kw, "node_index", Py_BuildValue("i", node_offset)) == -1)
+ goto fail;
/* pass the position */
- if (PyDict_SetItemString(kw, "_start_line", Py_BuildValue("i", jsnode->pn_pos.begin.lineno-1)) == -1)
+ if (PyObject_SetAttrString(kw, "_start_line", Py_BuildValue("i", jsnode->pn_pos.begin.lineno-1)) == -1)
goto fail;
- if (PyDict_SetItemString(kw, "_start_col", Py_BuildValue("i", jsnode->pn_pos.begin.index)) == -1)
+ if (PyObject_SetAttrString(kw, "_start_col", Py_BuildValue("i", jsnode->pn_pos.begin.index)) == -1)
goto fail;
- if (PyDict_SetItemString(kw, "_end_line", Py_BuildValue("i", jsnode->pn_pos.end.lineno-1)) == -1)
+ if (PyObject_SetAttrString(kw, "_end_line", Py_BuildValue("i", jsnode->pn_pos.end.lineno-1)) == -1)
goto fail;
- if (PyDict_SetItemString(kw, "_end_col", Py_BuildValue("i", jsnode->pn_pos.end.index)) == -1)
+ if (PyObject_SetAttrString(kw, "_end_col", Py_BuildValue("i", jsnode->pn_pos.end.index)) == -1)
goto fail;
if ((jsnode->pn_type == TOK_NAME || jsnode->pn_type == TOK_DOT ||
jsnode->pn_type == TOK_STRING) && ATOM_IS_STRING(jsnode->pn_atom)) {
/* Convert the atom to a string. */
- if (PyDict_SetItemString(kw, "atom", atom_to_string(jsnode->pn_atom)) == -1)
+ if (PyObject_SetAttrString(kw, "atom", atom_to_string(jsnode->pn_atom)) == -1)
goto fail;
}
- if (PyDict_SetItemString(kw, "opcode", Py_BuildValue("i", OPCODE_TO_NUM(jsnode->pn_op))) == -1)
+ if (PyObject_SetAttrString(kw, "opcode", Py_BuildValue("i", OPCODE_TO_NUM(jsnode->pn_op))) == -1)
goto fail;
if (jsnode->pn_type == TOK_NUMBER) {
- if (PyDict_SetItemString(kw, "dval", Py_BuildValue("d", jsnode->pn_dval)) == -1)
+ if (PyObject_SetAttrString(kw, "dval", Py_BuildValue("d", jsnode->pn_dval)) == -1)
goto fail;
}
@@ -221,7 +226,7 @@
Py_INCREF(Py_None);
fn_name = Py_None;
}
- if (PyDict_SetItemString(kw, "fn_name", fn_name) == -1)
+ if (PyObject_SetAttrString(kw, "fn_name", fn_name) == -1)
goto fail;
/* get the function arguments */
@@ -251,19 +256,19 @@
name = atom_to_string(JSID_TO_ATOM(scope_property->id));
PyTuple_SET_ITEM(fn_args, (uint16)scope_property->shortid, name);
}
- if (PyDict_SetItemString(kw, "fn_args", fn_args) == -1)
+ if (PyObject_SetAttrString(kw, "fn_args", fn_args) == -1)
goto fail;
}
else if (jsnode->pn_type == TOK_RB) {
PyObject* end_comma = PyBool_FromLong(jsnode->pn_extra & PNX_ENDCOMMA);
- if (PyDict_SetItemString(kw, "end_comma", end_comma) == -1)
+ if (PyObject_SetAttrString(kw, "end_comma", end_comma) == -1)
goto fail;
}
switch (jsnode->pn_arity) {
case PN_FUNC:
kids = PyTuple_New(1);
- if (traverse_node(context, jsnode->pn_body, kids, 0) == -1)
+ if (traverse_node(context, jsnode->pn_body, kw, kids, 0) == -1)
return -1;
break;
@@ -272,7 +277,7 @@
int i;
kids = PyTuple_New(jsnode->pn_count);
for (i = 0, p = jsnode->pn_head; p; p = p->pn_next, i++) {
- if (traverse_node(context, p, kids, i) == -1)
+ if (traverse_node(context, p, kw, kids, i) == -1)
return -1;
}
}
@@ -280,31 +285,31 @@
case PN_TERNARY:
kids = PyTuple_New(3);
- if (traverse_node(context, jsnode->pn_kid1, kids, 0) == -1)
+ if (traverse_node(context, jsnode->pn_kid1, kw, kids, 0) == -1)
return -1;
- if (traverse_node(context, jsnode->pn_kid2, kids, 1) == -1)
+ if (traverse_node(context, jsnode->pn_kid2, kw, kids, 1) == -1)
return -1;
- if (traverse_node(context, jsnode->pn_kid3, kids, 2) == -1)
+ if (traverse_node(context, jsnode->pn_kid3, kw, kids, 2) == -1)
return -1;
break;
case PN_BINARY:
kids = PyTuple_New(2);
- if (traverse_node(context, jsnode->pn_left, kids, 0) == -1)
+ if (traverse_node(context, jsnode->pn_left, kw, kids, 0) == -1)
return -1;
- if (traverse_node(context, jsnode->pn_right, kids, 1) == -1)
+ if (traverse_node(context, jsnode->pn_right, kw, kids, 1) == -1)
return -1;
break;
case PN_UNARY:
kids = PyTuple_New(1);
- if (traverse_node(context, jsnode->pn_kid, kids, 0) == -1)
+ if (traverse_node(context, jsnode->pn_kid, kw, kids, 0) == -1)
return -1;
break;
case PN_NAME:
kids = PyTuple_New(1);
- if (traverse_node(context, jsnode->pn_expr, kids, 0) == -1)
+ if (traverse_node(context, jsnode->pn_expr, kw, kids, 0) == -1)
return -1;
break;
@@ -313,7 +318,7 @@
break;
}
- if (PyDict_SetItemString(kw, "kids", kids) == -1)
+ if (PyObject_SetAttrString(kw, "kids", kids) == -1)
goto fail;
return 0;
@@ -346,9 +351,14 @@
error = "encountered an unknown error";
/* validate arguments */
- if (!PyArg_ParseTuple(args, "sO", &m.script, &m.ctx_data.error_callback))
+ if (!PyArg_ParseTuple(args, "sOO", &m.script, &m.ctx_data.node_class, &m.ctx_data.error_callback))
return NULL;
+ if (!PyCallable_Check(m.ctx_data.node_class)) {
+ PyErr_SetString(PyExc_ValueError, "\"node_class\" must be callable");
+ return NULL;
+ }
+
if (!PyCallable_Check(m.ctx_data.error_callback)) {
PyErr_SetString(PyExc_ValueError, "\"error\" must be callable");
return NULL;
@@ -399,7 +409,7 @@
}
m.kids = PyTuple_New(1);
- if (traverse_node(m.context, m.jsnode, m.kids, 0) == -1) {
+ if (traverse_node(m.context, m.jsnode, Py_None, m.kids, 0) == -1) {
error = "";
goto cleanup;
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-03 18:41:16
|
Revision: 156
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=156&view=rev
Author: matthiasmiller
Date: 2008-03-03 10:41:11 -0800 (Mon, 03 Mar 2008)
Log Message:
-----------
use __str__ instead of __repr__
Modified Paths:
--------------
trunk/pyjsl/parse.py
Modified: trunk/pyjsl/parse.py
===================================================================
--- trunk/pyjsl/parse.py 2008-03-03 18:31:17 UTC (rev 155)
+++ trunk/pyjsl/parse.py 2008-03-03 18:41:11 UTC (rev 156)
@@ -26,7 +26,7 @@
if self.col > other.col:
return 1
return 0
- def __repr__(self):
+ def __str__(self):
return '(line %i, col %i)' % (self.line+1, self.col+1)
class NodePositions():
@@ -102,7 +102,7 @@
self._end_pos = NodePos(self._end_line, self._end_col)
return self._end_pos
- def __repr__(self):
+ def __str__(self):
kind = self.kind
if not kind:
kind = '(none)'
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-03 18:31:32
|
Revision: 155
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=155&view=rev
Author: matthiasmiller
Date: 2008-03-03 10:31:17 -0800 (Mon, 03 Mar 2008)
Log Message:
-----------
set eol styles
Property Changed:
----------------
trunk/COPYING
trunk/DEVELOPMENT
trunk/INSTALL
trunk/jsl.py
trunk/pyjsl/__init__.py
trunk/pyjsl/conf.py
trunk/pyjsl/lint.py
trunk/pyjsl/parse.py
trunk/pyjsl/util.py
trunk/pyjsl/visitation.py
trunk/pyjsl/warnings.py
trunk/pyspidermonkey/pyspidermonkey.c
trunk/pyspidermonkey/tokens.tbl
trunk/setup.py
trunk/test.py
Property changes on: trunk/COPYING
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/DEVELOPMENT
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/INSTALL
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/jsl.py
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/pyjsl/__init__.py
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/pyjsl/conf.py
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/pyjsl/lint.py
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/pyjsl/parse.py
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/pyjsl/util.py
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/pyjsl/visitation.py
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/pyjsl/warnings.py
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/pyspidermonkey/pyspidermonkey.c
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/pyspidermonkey/tokens.tbl
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/setup.py
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/test.py
___________________________________________________________________
Name: eol-style
+ native
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-03 18:26:20
|
Revision: 154
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=154&view=rev
Author: matthiasmiller
Date: 2008-03-03 10:26:12 -0800 (Mon, 03 Mar 2008)
Log Message:
-----------
optimize _Node construction
Modified Paths:
--------------
trunk/pyjsl/parse.py
trunk/pyspidermonkey/pyspidermonkey.c
Modified: trunk/pyjsl/parse.py
===================================================================
--- trunk/pyjsl/parse.py 2008-03-02 03:30:04 UTC (rev 153)
+++ trunk/pyjsl/parse.py 2008-03-03 18:26:12 UTC (rev 154)
@@ -1,341 +1,325 @@
-#!/usr/bin/python
-""" Parses a script into nodes. """
-import bisect
-import re
-import unittest
-
-import pyspidermonkey
-from pyspidermonkey import tok, op
-
-_tok_names = dict(zip(
- [getattr(tok, prop) for prop in dir(tok)],
- ['tok.%s' % prop for prop in dir(tok)]
-))
-
-class NodePos():
- def __init__(self, line, col):
- self.line = line
- self.col = col
- def __cmp__(self, other):
- if self.line < other.line:
- return -1
- if self.line > other.line:
- return 1
- if self.col < other.col:
- return -1
- if self.col > other.col:
- return 1
- return 0
- def __repr__(self):
- return '(line %i, col %i)' % (self.line+1, self.col+1)
-
-class NodePositions():
- " Given a string, allows [x] lookups for NodePos line and column numbers."
- def __init__(self, text):
- # Find the length of each line and incrementally sum all of the lengths
- # to determine the ending position of each line.
- self._lines = text.splitlines(True)
- lines = [0] + [len(x) for x in self._lines]
- for x in range(1, len(lines)):
- lines[x] += lines[x-1]
- self._line_offsets = lines
- def from_offset(self, offset):
- line = bisect.bisect(self._line_offsets, offset)-1
- col = offset - self._line_offsets[line]
- return NodePos(line, col)
- def to_offset(self, pos):
- offset = self._line_offsets[pos.line] + pos.col
- assert offset <= self._line_offsets[pos.line+1] # out-of-bounds col num
- return offset
- def text(self, start, end):
- assert start <= end
- # Trim the ending first in case it's a single line.
- lines = self._lines[start.line:end.line+1]
- lines[-1] = lines[-1][:end.col+1]
- lines[0] = lines[0][start.col:]
- return ''.join(lines)
-
-class NodeRanges():
- def __init__(self):
- self._offsets = []
- def add(self, start, end):
- i = bisect.bisect_left(self._offsets, start)
- if i % 2 == 1:
- i -= 1
- start = self._offsets[i]
-
- end = end + 1
- j = bisect.bisect_left(self._offsets, end)
- if j % 2 == 1:
- end = self._offsets[j]
- j += 1
-
- self._offsets[i:j] = [start,end]
- def has(self, pos):
- return bisect.bisect_right(self._offsets, pos) % 2 == 1
-
-class _Node():
- def __init__(self, kwargs):
- def _to_node(kid):
- if kid:
- return _Node(kid)
- self.kind = kwargs['type']
- kwargs['opcode'] = kwargs['opcode']
- self.opcode = kwargs['opcode']
- self.kids = tuple([_to_node(kid) for kid in kwargs['kids']])
- for kid in self.kids:
- if kid:
- kid.parent = self
- if 'atom' in kwargs:
- self.atom = kwargs['atom']
- if 'dval' in kwargs:
- self.dval = kwargs['dval']
- if 'fn_name' in kwargs:
- self.fn_name = kwargs['fn_name']
- if 'fn_args' in kwargs:
- self.fn_args = kwargs['fn_args']
- if 'end_comma' in kwargs:
- self.end_comma = kwargs['end_comma']
- self.args = kwargs
- self.node_index = kwargs['node_index']
- self.parent = None
- self.start_line = kwargs['start_row']
- self._start_pos = None
- self._end_pos = None
-
- def add_child(self, node):
- if node:
- node.node_index = len(self.kids)
- node.parent = self
- self.kids.append(node)
-
- def start_pos(self):
- self._start_pos = self._start_pos or \
- NodePos(self.args['start_row'], self.args['start_col'])
- return self._start_pos
-
- def end_pos(self):
- self._end_pos = self._end_pos or \
- NodePos(self.args['end_row'], self.args['end_col'])
- return self._end_pos
-
- def __repr__(self):
- kind = self.kind
- if not kind:
- kind = '(none)'
- return '%s>%s' % (_tok_names[kind], str(self.kids))
-
- def is_equivalent(self, other, are_functions_equiv=False):
- if not other:
- return False
-
- # Bail out for functions
- if not are_functions_equiv:
- if self.kind == tok.FUNCTION:
- return False
- if self.kind == tok.LP and self.opcode == op.CALL:
- return False
-
- if self.kind != other.kind:
- return False
- if self.opcode != other.opcode:
- return False
-
- # Check atoms on names, properties, and string constants
- if self.kind in (tok.NAME, tok.DOT, tok.STRING) and self.atom != other.atom:
- return False
-
- # Check values on numbers
- if self.kind == tok.NUMBER and self.dval != other.dval:
- return False
-
- # Compare child nodes
- if len(self.kids) != len(other.kids):
- return False
- for i in range(0, len(self.kids)):
- # Watch for dead nodes
- if not self.kids[i]:
- if not other.kids[i]: return True
- else: return False
- if not self.kids[i].is_equivalent(other.kids[i]):
- return False
-
- return True
-
-def _parse_comments(script, root, node_positions, ignore_ranges):
- pos = 0
- single_line_re = r"//[^\r\n]*"
- multi_line_re = r"/\*(.*?)\*/"
- full_re = "(%s)|(%s)" % (single_line_re, multi_line_re)
- comment_re = re.compile(full_re, re.DOTALL)
-
- comments = []
- while True:
- match = comment_re.search(script, pos)
- if not match:
- return comments
-
- # Get the comment text
- comment_text = script[match.start():match.end()]
- if comment_text.startswith('/*'):
- comment_text = comment_text[2:-2]
- opcode = 'JSOP_C_COMMENT'
- else:
- comment_text = comment_text[2:]
- opcode = 'JSOP_CPP_COMMENT'
- opcode = opcode[5:].lower()
-
- start_offset = match.start()+1
- end_offset = match.end()
-
- # Make sure it doesn't start in a string or regexp
- if not ignore_ranges.has(start_offset):
- start_pos = node_positions.from_offset(start_offset)
- end_pos = node_positions.from_offset(end_offset)
- kwargs = {
- 'type': 'COMMENT',
- 'atom': comment_text,
- 'opcode': opcode,
- 'start_row': start_pos.line,
- 'start_col': start_pos.col,
- 'end_row': end_pos.line,
- 'end_col': end_pos.col,
- 'kids': [],
- 'node_index': None
- }
- comment_node = _Node(kwargs)
- comments.append(comment_node)
- pos = match.end()
- else:
- pos = match.start()+1
-
-def parse(script, error_callback):
- def _wrapped_callback(line, col, msg):
- assert msg.startswith('JSMSG_')
- msg = msg[6:].lower()
- error_callback(line, col, msg)
-
- positions = NodePositions(script)
-
- roots = []
- nodes = []
- comment_ignore_ranges = NodeRanges()
- def process(node):
- if node.kind == tok.NUMBER:
- node.atom = positions.text(node.start_pos(), node.end_pos())
- elif node.kind == tok.STRING or \
- (node.kind == tok.OBJECT and node.opcode == op.REGEXP):
- start_offset = positions.to_offset(node.start_pos())
- end_offset = positions.to_offset(node.end_pos())
- comment_ignore_ranges.add(start_offset, end_offset)
- for kid in node.kids:
- if kid:
- process(kid)
- def pop():
- nodes.pop()
-
- roots = pyspidermonkey.traverse(script, _wrapped_callback)
- assert len(roots) == 1
- root_node = _Node(roots[0])
- process(root_node)
-
- comments = _parse_comments(script, root_node, positions, comment_ignore_ranges)
- return root_node, comments
-
-def _dump_node(node, depth=0):
- print '. '*depth,
- if node is None:
- print '(none)'
- else:
- print _tok_names[node.kind], '\t', node.args
- for node in node.kids:
- _dump_node(node, depth+1)
-
-def dump_tree(script):
- def error_callback(line, col, msg):
- print '(%i, %i): %s', (line, col, msg)
- node, comments = parse(script, error_callback)
- _dump_node(node)
-
-class TestComments(unittest.TestCase):
- def _test(self, script, expected_comments):
- root, comments = parse(script, lambda line, col, msg: None)
- encountered_comments = [node.atom for node in comments]
- self.assertEquals(encountered_comments, list(expected_comments))
- def testSimpleComments(self):
- self._test('re = /\//g', ())
- self._test('re = /\///g', ())
- self._test('re = /\////g', ('g',))
- def testCComments(self):
- self._test('/*a*//*b*/', ('a', 'b'))
- self._test('/*a\r\na*//*b\r\nb*/', ('a\r\na', 'b\r\nb'))
- self._test('a//*b*/c', ('*b*/c',))
- self._test('a///*b*/c', ('/*b*/c',))
- self._test('a/*//*/;', ('//',))
- self._test('a/*b*/+/*c*/d', ('b', 'c'))
-
-class TestNodePositions(unittest.TestCase):
- def _test(self, text, expected_lines, expected_cols):
- # Get a NodePos list
- positions = NodePositions(text)
- positions = [positions.from_offset(i) for i in range(0, len(text))]
- encountered_lines = ''.join([str(x.line) for x in positions])
- encountered_cols = ''.join([str(x.col) for x in positions])
- self.assertEquals(encountered_lines, expected_lines.replace(' ', ''))
- self.assertEquals(encountered_cols, expected_cols.replace(' ', ''))
- def testSimple(self):
- self._test(
- 'abc\r\ndef\nghi\n\nj',
- '0000 0 1111 2222 3 4',
- '0123 4 0123 0123 0 0'
- )
- self._test(
- '\rabc',
- '0 111',
- '0 012'
- )
- def testText(self):
- pos = NodePositions('abc\r\ndef\n\nghi')
- self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 0)), 'a')
- self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 2)), 'abc')
- self.assertEquals(pos.text(NodePos(0, 2), NodePos(1, 2)), 'c\r\ndef')
- def testOffset(self):
- pos = NodePositions('abc\r\ndef\n\nghi')
- self.assertEquals(pos.to_offset(NodePos(0, 2)), 2)
- self.assertEquals(pos.to_offset(NodePos(1, 0)), 5)
- self.assertEquals(pos.to_offset(NodePos(3, 1)), 11)
-
-class TestNodeRanges(unittest.TestCase):
- def testAdd(self):
- r = NodeRanges()
- r.add(5, 10)
- self.assertEquals(r._offsets, [5,11])
- r.add(15, 20)
- self.assertEquals(r._offsets, [5,11,15,21])
- r.add(21,22)
- self.assertEquals(r._offsets, [5,11,15,23])
- r.add(4,5)
- self.assertEquals(r._offsets, [4,11,15,23])
- r.add(9,11)
- self.assertEquals(r._offsets, [4,12,15,23])
- r.add(10,20)
- self.assertEquals(r._offsets, [4,23])
- r.add(4,22)
- self.assertEquals(r._offsets, [4,23])
- r.add(30,30)
- self.assertEquals(r._offsets, [4,23,30,31])
- def testHas(self):
- r = NodeRanges()
- r.add(5, 10)
- r.add(15, 15)
- assert not r.has(4)
- assert r.has(5)
- assert r.has(6)
- assert r.has(9)
- assert r.has(10)
- assert not r.has(14)
- assert r.has(15)
- assert not r.has(16)
-if __name__ == '__main__':
- unittest.main()
-
+#!/usr/bin/python
+""" Parses a script into nodes. """
+import bisect
+import re
+import unittest
+
+import pyspidermonkey
+from pyspidermonkey import tok, op
+
+_tok_names = dict(zip(
+ [getattr(tok, prop) for prop in dir(tok)],
+ ['tok.%s' % prop for prop in dir(tok)]
+))
+
+class NodePos():
+ def __init__(self, line, col):
+ self.line = line
+ self.col = col
+ def __cmp__(self, other):
+ if self.line < other.line:
+ return -1
+ if self.line > other.line:
+ return 1
+ if self.col < other.col:
+ return -1
+ if self.col > other.col:
+ return 1
+ return 0
+ def __repr__(self):
+ return '(line %i, col %i)' % (self.line+1, self.col+1)
+
+class NodePositions():
+ " Given a string, allows [x] lookups for NodePos line and column numbers."
+ def __init__(self, text):
+ # Find the length of each line and incrementally sum all of the lengths
+ # to determine the ending position of each line.
+ self._lines = text.splitlines(True)
+ lines = [0] + [len(x) for x in self._lines]
+ for x in range(1, len(lines)):
+ lines[x] += lines[x-1]
+ self._line_offsets = lines
+ def from_offset(self, offset):
+ line = bisect.bisect(self._line_offsets, offset)-1
+ col = offset - self._line_offsets[line]
+ return NodePos(line, col)
+ def to_offset(self, pos):
+ offset = self._line_offsets[pos.line] + pos.col
+ assert offset <= self._line_offsets[pos.line+1] # out-of-bounds col num
+ return offset
+ def text(self, start, end):
+ assert start <= end
+ # Trim the ending first in case it's a single line.
+ lines = self._lines[start.line:end.line+1]
+ lines[-1] = lines[-1][:end.col+1]
+ lines[0] = lines[0][start.col:]
+ return ''.join(lines)
+
+class NodeRanges():
+ def __init__(self):
+ self._offsets = []
+ def add(self, start, end):
+ i = bisect.bisect_left(self._offsets, start)
+ if i % 2 == 1:
+ i -= 1
+ start = self._offsets[i]
+
+ end = end + 1
+ j = bisect.bisect_left(self._offsets, end)
+ if j % 2 == 1:
+ end = self._offsets[j]
+ j += 1
+
+ self._offsets[i:j] = [start,end]
+ def has(self, pos):
+ return bisect.bisect_right(self._offsets, pos) % 2 == 1
+
+class _Node():
+ def __init__(self, kids, parent=None, **kwargs):
+ _to_node = lambda kid: kid and _Node(parent=self, **kid)
+ self.__dict__.update(kwargs)
+ self.args = kwargs
+ self.parent = parent
+ self.kids = map(_to_node, kids)
+
+ def add_child(self, node):
+ if node:
+ node.node_index = len(self.kids)
+ node.parent = self
+ self.kids.append(node)
+
+ def start_pos(self):
+ try:
+ return self._start_pos
+ except AttributeError:
+ self._start_pos = NodePos(self._start_line, self._start_col)
+ return self._start_pos
+
+ def end_pos(self):
+ try:
+ return self._end_pos
+ except AttributeError:
+ self._end_pos = NodePos(self._end_line, self._end_col)
+ return self._end_pos
+
+ def __repr__(self):
+ kind = self.kind
+ if not kind:
+ kind = '(none)'
+ return '%s>%s' % (_tok_names[kind], str(self.kids))
+
+ def is_equivalent(self, other, are_functions_equiv=False):
+ if not other:
+ return False
+
+ # Bail out for functions
+ if not are_functions_equiv:
+ if self.kind == tok.FUNCTION:
+ return False
+ if self.kind == tok.LP and self.opcode == op.CALL:
+ return False
+
+ if self.kind != other.kind:
+ return False
+ if self.opcode != other.opcode:
+ return False
+
+ # Check atoms on names, properties, and string constants
+ if self.kind in (tok.NAME, tok.DOT, tok.STRING) and self.atom != other.atom:
+ return False
+
+ # Check values on numbers
+ if self.kind == tok.NUMBER and self.dval != other.dval:
+ return False
+
+ # Compare child nodes
+ if len(self.kids) != len(other.kids):
+ return False
+ for i in range(0, len(self.kids)):
+ # Watch for dead nodes
+ if not self.kids[i]:
+ if not other.kids[i]: return True
+ else: return False
+ if not self.kids[i].is_equivalent(other.kids[i]):
+ return False
+
+ return True
+
+def _parse_comments(script, root, node_positions, ignore_ranges):
+ pos = 0
+ single_line_re = r"//[^\r\n]*"
+ multi_line_re = r"/\*(.*?)\*/"
+ full_re = "(%s)|(%s)" % (single_line_re, multi_line_re)
+ comment_re = re.compile(full_re, re.DOTALL)
+
+ comments = []
+ while True:
+ match = comment_re.search(script, pos)
+ if not match:
+ return comments
+
+ # Get the comment text
+ comment_text = script[match.start():match.end()]
+ if comment_text.startswith('/*'):
+ comment_text = comment_text[2:-2]
+ opcode = 'JSOP_C_COMMENT'
+ else:
+ comment_text = comment_text[2:]
+ opcode = 'JSOP_CPP_COMMENT'
+ opcode = opcode[5:].lower()
+
+ start_offset = match.start()+1
+ end_offset = match.end()
+
+ # Make sure it doesn't start in a string or regexp
+ if not ignore_ranges.has(start_offset):
+ start_pos = node_positions.from_offset(start_offset)
+ end_pos = node_positions.from_offset(end_offset)
+ kwargs = {
+ 'type': 'COMMENT',
+ 'atom': comment_text,
+ 'opcode': opcode,
+ '_start_line': start_pos.line,
+ '_start_col': start_pos.col,
+ '_end_line': end_pos.line,
+ '_end_col': end_pos.col,
+ 'parent': None,
+ 'kids': [],
+ 'node_index': None
+ }
+ comment_node = _Node(**kwargs)
+ comments.append(comment_node)
+ pos = match.end()
+ else:
+ pos = match.start()+1
+
+def parse(script, error_callback):
+ def _wrapped_callback(line, col, msg):
+ assert msg.startswith('JSMSG_')
+ msg = msg[6:].lower()
+ error_callback(line, col, msg)
+
+ positions = NodePositions(script)
+
+ roots = []
+ nodes = []
+ comment_ignore_ranges = NodeRanges()
+ def process(node):
+ if node.kind == tok.NUMBER:
+ node.atom = positions.text(node.start_pos(), node.end_pos())
+ elif node.kind == tok.STRING or \
+ (node.kind == tok.OBJECT and node.opcode == op.REGEXP):
+ start_offset = positions.to_offset(node.start_pos())
+ end_offset = positions.to_offset(node.end_pos())
+ comment_ignore_ranges.add(start_offset, end_offset)
+ for kid in node.kids:
+ if kid:
+ process(kid)
+ def pop():
+ nodes.pop()
+
+ roots = pyspidermonkey.traverse(script, _wrapped_callback)
+ assert len(roots) == 1
+ root_node = _Node(**roots[0])
+ process(root_node)
+
+ comments = _parse_comments(script, root_node, positions, comment_ignore_ranges)
+ return root_node, comments
+
+def _dump_node(node, depth=0):
+ print '. '*depth,
+ if node is None:
+ print '(none)'
+ else:
+ print _tok_names[node.kind], '\t', node.args
+ for node in node.kids:
+ _dump_node(node, depth+1)
+
+def dump_tree(script):
+ def error_callback(line, col, msg):
+ print '(%i, %i): %s', (line, col, msg)
+ node, comments = parse(script, error_callback)
+ _dump_node(node)
+
+class TestComments(unittest.TestCase):
+ def _test(self, script, expected_comments):
+ root, comments = parse(script, lambda line, col, msg: None)
+ encountered_comments = [node.atom for node in comments]
+ self.assertEquals(encountered_comments, list(expected_comments))
+ def testSimpleComments(self):
+ self._test('re = /\//g', ())
+ self._test('re = /\///g', ())
+ self._test('re = /\////g', ('g',))
+ def testCComments(self):
+ self._test('/*a*//*b*/', ('a', 'b'))
+ self._test('/*a\r\na*//*b\r\nb*/', ('a\r\na', 'b\r\nb'))
+ self._test('a//*b*/c', ('*b*/c',))
+ self._test('a///*b*/c', ('/*b*/c',))
+ self._test('a/*//*/;', ('//',))
+ self._test('a/*b*/+/*c*/d', ('b', 'c'))
+
+class TestNodePositions(unittest.TestCase):
+ def _test(self, text, expected_lines, expected_cols):
+ # Get a NodePos list
+ positions = NodePositions(text)
+ positions = [positions.from_offset(i) for i in range(0, len(text))]
+ encountered_lines = ''.join([str(x.line) for x in positions])
+ encountered_cols = ''.join([str(x.col) for x in positions])
+ self.assertEquals(encountered_lines, expected_lines.replace(' ', ''))
+ self.assertEquals(encountered_cols, expected_cols.replace(' ', ''))
+ def testSimple(self):
+ self._test(
+ 'abc\r\ndef\nghi\n\nj',
+ '0000 0 1111 2222 3 4',
+ '0123 4 0123 0123 0 0'
+ )
+ self._test(
+ '\rabc',
+ '0 111',
+ '0 012'
+ )
+ def testText(self):
+ pos = NodePositions('abc\r\ndef\n\nghi')
+ self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 0)), 'a')
+ self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 2)), 'abc')
+ self.assertEquals(pos.text(NodePos(0, 2), NodePos(1, 2)), 'c\r\ndef')
+ def testOffset(self):
+ pos = NodePositions('abc\r\ndef\n\nghi')
+ self.assertEquals(pos.to_offset(NodePos(0, 2)), 2)
+ self.assertEquals(pos.to_offset(NodePos(1, 0)), 5)
+ self.assertEquals(pos.to_offset(NodePos(3, 1)), 11)
+
+class TestNodeRanges(unittest.TestCase):
+ def testAdd(self):
+ r = NodeRanges()
+ r.add(5, 10)
+ self.assertEquals(r._offsets, [5,11])
+ r.add(15, 20)
+ self.assertEquals(r._offsets, [5,11,15,21])
+ r.add(21,22)
+ self.assertEquals(r._offsets, [5,11,15,23])
+ r.add(4,5)
+ self.assertEquals(r._offsets, [4,11,15,23])
+ r.add(9,11)
+ self.assertEquals(r._offsets, [4,12,15,23])
+ r.add(10,20)
+ self.assertEquals(r._offsets, [4,23])
+ r.add(4,22)
+ self.assertEquals(r._offsets, [4,23])
+ r.add(30,30)
+ self.assertEquals(r._offsets, [4,23,30,31])
+ def testHas(self):
+ r = NodeRanges()
+ r.add(5, 10)
+ r.add(15, 15)
+ assert not r.has(4)
+ assert r.has(5)
+ assert r.has(6)
+ assert r.has(9)
+ assert r.has(10)
+ assert not r.has(14)
+ assert r.has(15)
+ assert not r.has(16)
+if __name__ == '__main__':
+ unittest.main()
+
Modified: trunk/pyspidermonkey/pyspidermonkey.c
===================================================================
--- trunk/pyspidermonkey/pyspidermonkey.c 2008-03-02 03:30:04 UTC (rev 153)
+++ trunk/pyspidermonkey/pyspidermonkey.c 2008-03-03 18:26:12 UTC (rev 154)
@@ -173,19 +173,19 @@
PyTuple_SET_ITEM(tuple, node_offset, kw);
- if (PyDict_SetItemString(kw, "type", Py_BuildValue("i", TOK_TO_NUM(jsnode->pn_type))) == -1)
+ if (PyDict_SetItemString(kw, "kind", 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;
/* pass the position */
- if (PyDict_SetItemString(kw, "start_row", Py_BuildValue("i", jsnode->pn_pos.begin.lineno-1)) == -1)
+ if (PyDict_SetItemString(kw, "_start_line", Py_BuildValue("i", jsnode->pn_pos.begin.lineno-1)) == -1)
goto fail;
- if (PyDict_SetItemString(kw, "start_col", Py_BuildValue("i", jsnode->pn_pos.begin.index)) == -1)
+ if (PyDict_SetItemString(kw, "_start_col", Py_BuildValue("i", jsnode->pn_pos.begin.index)) == -1)
goto fail;
- if (PyDict_SetItemString(kw, "end_row", Py_BuildValue("i", jsnode->pn_pos.end.lineno-1)) == -1)
+ if (PyDict_SetItemString(kw, "_end_line", Py_BuildValue("i", jsnode->pn_pos.end.lineno-1)) == -1)
goto fail;
- if (PyDict_SetItemString(kw, "end_col", Py_BuildValue("i", jsnode->pn_pos.end.index)) == -1)
+ if (PyDict_SetItemString(kw, "_end_col", Py_BuildValue("i", jsnode->pn_pos.end.index)) == -1)
goto fail;
if ((jsnode->pn_type == TOK_NAME || jsnode->pn_type == TOK_DOT ||
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-02 03:30:08
|
Revision: 153
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=153&view=rev
Author: matthiasmiller
Date: 2008-03-01 19:30:04 -0800 (Sat, 01 Mar 2008)
Log Message:
-----------
show tok.TOKENNAME when printing tokens
Modified Paths:
--------------
trunk/pyjsl/parse.py
Modified: trunk/pyjsl/parse.py
===================================================================
--- trunk/pyjsl/parse.py 2008-03-01 19:05:07 UTC (rev 152)
+++ trunk/pyjsl/parse.py 2008-03-02 03:30:04 UTC (rev 153)
@@ -7,6 +7,11 @@
import pyspidermonkey
from pyspidermonkey import tok, op
+_tok_names = dict(zip(
+ [getattr(tok, prop) for prop in dir(tok)],
+ ['tok.%s' % prop for prop in dir(tok)]
+))
+
class NodePos():
def __init__(self, line, col):
self.line = line
@@ -118,7 +123,7 @@
kind = self.kind
if not kind:
kind = '(none)'
- return '%s>%s' % (kind, str(self.kids))
+ return '%s>%s' % (_tok_names[kind], str(self.kids))
def is_equivalent(self, other, are_functions_equiv=False):
if not other:
@@ -242,7 +247,7 @@
if node is None:
print '(none)'
else:
- print node.kind, '\t', node.args
+ print _tok_names[node.kind], '\t', node.args
for node in node.kids:
_dump_node(node, depth+1)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-01 19:05:09
|
Revision: 152
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=152&view=rev
Author: matthiasmiller
Date: 2008-03-01 11:05:07 -0800 (Sat, 01 Mar 2008)
Log Message:
-----------
fix crash when functions have too many parameters
Modified Paths:
--------------
trunk/spidermonkey/src/jsdbgapi.c
Modified: trunk/spidermonkey/src/jsdbgapi.c
===================================================================
--- trunk/spidermonkey/src/jsdbgapi.c 2008-03-01 19:04:30 UTC (rev 151)
+++ trunk/spidermonkey/src/jsdbgapi.c 2008-03-01 19:05:07 UTC (rev 152)
@@ -1187,8 +1187,10 @@
}
n = scope->entryCount;
+#if 0
if (n > scope->map.nslots)
n = scope->map.nslots;
+#endif
pd = (JSPropertyDesc *) JS_malloc(cx, (size_t)n * sizeof(JSPropertyDesc));
if (!pd)
return JS_FALSE;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-01 19:04:32
|
Revision: 151
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=151&view=rev
Author: matthiasmiller
Date: 2008-03-01 11:04:30 -0800 (Sat, 01 Mar 2008)
Log Message:
-----------
fix Makefile for Windows
Modified Paths:
--------------
trunk/Makefile.SpiderMonkey
Modified: trunk/Makefile.SpiderMonkey
===================================================================
--- trunk/Makefile.SpiderMonkey 2008-03-01 18:45:07 UTC (rev 150)
+++ trunk/Makefile.SpiderMonkey 2008-03-01 19:04:30 UTC (rev 151)
@@ -53,7 +53,10 @@
$(COPY_LIB): $(BUILD_DIR) $(ORIG_LIB)
cp $(ORIG_LIB) $(COPY_LIB)
-$(COPY_DLL): $(BUILD_DIR) $(ORIG_LIB)
+$(DISTUTILS_DIR): $(DISTUTILS_DIR_MAKEFILE)
+ mkdir -p $(DISTUTILS_DIR)
+
+$(COPY_DLL): $(DISTUTILS_DIR) $(ORIG_LIB)
cp $(ORIG_DLL) $(COPY_DLL)
$(OS_HEADER): $(BUILD_DIR)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-01 18:45:09
|
Revision: 150
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=150&view=rev
Author: matthiasmiller
Date: 2008-03-01 10:45:07 -0800 (Sat, 01 Mar 2008)
Log Message:
-----------
add svn_load_dirs conf file
Added Paths:
-----------
trunk/svn_load_dirs.conf
Added: trunk/svn_load_dirs.conf
===================================================================
--- trunk/svn_load_dirs.conf (rev 0)
+++ trunk/svn_load_dirs.conf 2008-03-01 18:45:07 UTC (rev 150)
@@ -0,0 +1 @@
+.* cont svn:eol-style native
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
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.
|
|
From: <mat...@us...> - 2008-03-01 17:32:58
|
Revision: 148
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=148&view=rev
Author: matthiasmiller
Date: 2008-03-01 09:32:55 -0800 (Sat, 01 Mar 2008)
Log Message:
-----------
include some notes on style guidelines and upgrading SpiderMonkey
Added Paths:
-----------
trunk/DEVELOPMENT
Removed Paths:
-------------
trunk/TODO
Copied: trunk/DEVELOPMENT (from rev 147, trunk/TODO)
===================================================================
--- trunk/DEVELOPMENT (rev 0)
+++ trunk/DEVELOPMENT 2008-03-01 17:32:55 UTC (rev 148)
@@ -0,0 +1,31 @@
+** STYLE GUIDELINES
+
+> Use tabs instead of spaces (for now)
+> All lines should be 79 characters or less
+> For everything else, follow http://www.python.org/dev/peps/pep-0008/ as much
+ as possible.
+
+
+** TODO
+
+> implement conf file
+> support HTML parsing
+> support JScript extensions
+> implement semicolons warning
+> implement line break warning
+> add test for syntax error
+
+
+** UPGRADING SPIDERMONKEY
+
+Use the following command to upgrade SpiderMonkey. Replace X.X.X with the
+version number. js-X.X.X is the directory containing the new version of
+SpiderMonkey. Use a relative path for pretty commit messages.
+
+svn_load_dirs.pl \
+ -t X.X.X \
+ -p svn_load_dirs.conf \
+ https://javascriptlint.svn.sourceforge.net/svnroot/javascriptlint/vendorsrc/Mozilla.org/js \
+ current \
+ js-X.X.X
+
Deleted: trunk/TODO
===================================================================
--- trunk/TODO 2008-03-01 17:21:01 UTC (rev 147)
+++ trunk/TODO 2008-03-01 17:32:55 UTC (rev 148)
@@ -1,13 +0,0 @@
-
-> implement conf file
-
-> support HTML parsing
-
-> support JScript extensions
-
-> implement semicolons warning
-
-> implement line break warning
-
-> add test for syntax error
-
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-01 17:21:12
|
Revision: 147
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=147&view=rev
Author: matthiasmiller
Date: 2008-03-01 09:21:01 -0800 (Sat, 01 Mar 2008)
Log Message:
-----------
initial import of pyjsl
Added Paths:
-----------
trunk/COPYING
trunk/INSTALL
trunk/Makefile.SpiderMonkey
trunk/TODO
trunk/jsl.py
trunk/pyjsl/
trunk/pyjsl/__init__.py
trunk/pyjsl/conf.py
trunk/pyjsl/lint.py
trunk/pyjsl/parse.py
trunk/pyjsl/util.py
trunk/pyjsl/visitation.py
trunk/pyjsl/warnings.py
trunk/pyspidermonkey/
trunk/pyspidermonkey/pyspidermonkey.c
trunk/pyspidermonkey/tokens.tbl
trunk/setup.py
trunk/test.py
Property Changed:
----------------
trunk/
Property changes on: trunk
___________________________________________________________________
Name: svn:ignore
+ dist
build
*.pyc
Added: trunk/COPYING
===================================================================
--- trunk/COPYING (rev 0)
+++ trunk/COPYING 2008-03-01 17:21:01 UTC (rev 147)
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Added: trunk/INSTALL
===================================================================
--- trunk/INSTALL (rev 0)
+++ trunk/INSTALL 2008-03-01 17:21:01 UTC (rev 147)
@@ -0,0 +1,14 @@
+
+BUILDING FROM THE SUBVERSION TRUNK
+* Windows Prequisites:
+ * Visual Studio 2003
+ * Python
+ * MozillaBuild (http://developer.mozilla.org/en/docs/Windows_Build_Prerequisites)
+
+ Launch the MozillaBuild 7.1 batch file. (You may have to run this as an Administrator
+ on Windows Vista.) Run the commands in that shell.
+
+On all platforms:
+ $ make -f Makefile.SpiderMonkey
+ $ python setup.py build
+
Added: trunk/Makefile.SpiderMonkey
===================================================================
--- trunk/Makefile.SpiderMonkey (rev 0)
+++ trunk/Makefile.SpiderMonkey 2008-03-01 17:21:01 UTC (rev 147)
@@ -0,0 +1,67 @@
+
+SPIDERMONKEY_SRC=spidermonkey/src
+
+# Load the SpiderMonkey config to find the OS define
+# Also use this for the SO_SUFFIX
+BUILD_OPT=1
+DEPTH=$(SPIDERMONKEY_SRC)
+include $(SPIDERMONKEY_SRC)/config.mk
+SPIDERMONKEY_OS=$(firstword $(patsubst -D%, %, $(filter -DXP_%, $(OS_CFLAGS))))
+
+ifdef USE_MSVC
+JS_LIB=js32.lib
+else
+JS_LIB=libjs.a
+endif
+
+BUILD_DIR=build/spidermonkey
+
+# Use a dynamically-created makefile to determine the distutils output dir
+DISTUTILS_DIR_MAKEFILE=$(BUILD_DIR)/Makefile-distutils
+include $(DISTUTILS_DIR_MAKEFILE)
+
+ORIG_LIB=$(SPIDERMONKEY_SRC)/$(OBJDIR)/$(JS_LIB)
+COPY_LIB=$(BUILD_DIR)/$(JS_LIB)
+ORIG_DLL=$(SPIDERMONKEY_SRC)/$(OBJDIR)/js32.dll
+COPY_DLL=$(DISTUTILS_DIR)/js32.dll
+OS_HEADER=$(BUILD_DIR)/js_operating_system.h
+ORIG_JSAUTOCFG_H=$(SPIDERMONKEY_SRC)/$(OBJDIR)/jsautocfg.h
+COPY_JSAUTOCFG_H=$(BUILD_DIR)/jsautocfg.h
+
+ALL_TARGETS=$(COPY_LIB) $(OS_HEADER)
+ifndef PREBUILT_CPUCFG
+ALL_TARGETS+=$(COPY_JSAUTOCFG_H)
+endif
+
+ifeq ($(SPIDERMONKEY_OS),XP_WIN)
+ALL_TARGETS+=$(COPY_DLL)
+endif
+
+all: $(ALL_TARGETS)
+
+clean:
+ make -f Makefile.ref -C $(SPIDERMONKEY_SRC) BUILD_OPT=$(BUILD_OPT) clean
+ rm $(ORIG_LIB)
+ rm -R $(BUILD_DIR)
+
+$(DISTUTILS_DIR_MAKEFILE): Makefile.SpiderMonkey $(BUILD_DIR)
+ python -c "import setup; print 'DISTUTILS_DIR='+setup.get_lib_path()" >> $(DISTUTILS_DIR_MAKEFILE)
+
+$(BUILD_DIR):
+ mkdir -p $(BUILD_DIR)
+
+$(COPY_LIB): $(BUILD_DIR) $(ORIG_LIB)
+ cp $(ORIG_LIB) $(COPY_LIB)
+
+$(COPY_DLL): $(BUILD_DIR) $(ORIG_LIB)
+ cp $(ORIG_DLL) $(COPY_DLL)
+
+$(OS_HEADER): $(BUILD_DIR)
+ echo "#define $(SPIDERMONKEY_OS)" > $(OS_HEADER)
+
+$(COPY_JSAUTOCFG_H): $(ORIG_JSAUTOCFG_H)
+ cp $(ORIG_JSAUTOCFG_H) $(COPY_JSAUTOCFG_H)
+
+$(ORIG_LIB):
+ make -f Makefile.ref -C $(SPIDERMONKEY_SRC) BUILD_OPT=$(BUILD_OPT)
+
Added: trunk/TODO
===================================================================
--- trunk/TODO (rev 0)
+++ trunk/TODO 2008-03-01 17:21:01 UTC (rev 147)
@@ -0,0 +1,13 @@
+
+> implement conf file
+
+> support HTML parsing
+
+> support JScript extensions
+
+> implement semicolons warning
+
+> implement line break warning
+
+> add test for syntax error
+
Added: trunk/jsl.py
===================================================================
--- trunk/jsl.py (rev 0)
+++ trunk/jsl.py 2008-03-01 17:21:01 UTC (rev 147)
@@ -0,0 +1,147 @@
+#!/usr/bin/python
+import codecs
+import getopt
+import glob
+import os
+import sys
+import unittest
+
+try:
+ import setup
+except ImportError:
+ pass
+else:
+ sys.path.append(setup.get_lib_path())
+
+import pyjsl.conf
+import pyjsl.parse
+import pyjsl.util
+import test
+
+_lint_results = {
+ 'warnings': 0,
+ 'errors': 0
+}
+
+def get_test_files():
+ # Get a list of test files.
+ dir_ = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tests')
+
+ all_files = []
+ for root, dirs, files in os.walk(dir_):
+ all_files += [os.path.join(dir_, root, file) for file in files]
+ if '.svn' in dirs:
+ dirs.remove('.svn')
+ # TODO
+ if 'conf' in dirs:
+ dirs.remove('conf')
+ all_files.sort()
+ return all_files
+
+def run_tests():
+ for file in get_test_files():
+ if file.endswith('.htm') or file.endswith('.html'):
+ continue #TODO
+ elif file.endswith('.js'):
+ print file
+ try:
+ test.run(file)
+ except test.TestError, error:
+ print error
+
+def _dump(paths):
+ for path in paths:
+ script = pyjsl.util.readfile(path)
+ pyjsl.parse.dump_tree(script)
+
+def _lint(paths, conf):
+ def lint_error(path, line, col, errname):
+ _lint_results['warnings'] = _lint_results['warnings'] + 1
+ print '%s(%i): %s' % (path, line, errname)
+ pyjsl.lint.lint_files(paths, lint_error, conf=conf)
+
+def _resolve_paths(path, recurse):
+ if os.path.isfile(path):
+ return [path]
+ elif os.path.isdir(path):
+ dir = path
+ pattern = '*'
+ else:
+ dir, pattern = os.path.split(path)
+
+ # Build a list of directories
+ dirs = [dir]
+ if recurse:
+ for cur_root, cur_dirs, cur_files in os.walk(dir):
+ for name in cur_dirs:
+ dirs.append(os.path.join(cur_root, name))
+
+ # Glob all files.
+ paths = []
+ for dir in dirs:
+ paths.extend(glob.glob(os.path.join(dir, pattern)))
+ return paths
+
+def profile_enabled(func, *args, **kwargs):
+ import tempfile
+ import hotshot
+ import hotshot.stats
+ handle, filename = tempfile.mkstemp()
+ profile = hotshot.Profile(filename)
+ profile.runcall(func, *args, **kwargs)
+ profile.close()
+ stats = hotshot.stats.load(filename)
+ stats = stats.sort_stats("time")
+ stats.print_stats()
+def profile_disabled(func, *args, **kwargs):
+ func(*args, **kwargs)
+
+def usage():
+ print """
+Usage:
+ jsl [files]
+ --help (-h) print this help
+ --test (-t) run tests
+ --dump= dump this script
+"""
+
+if __name__ == '__main__':
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'ht:v', ['conf=', 'help', 'test', 'dump', 'unittest', 'profile'])
+ except getopt.GetoptError:
+ usage()
+ sys.exit(2)
+
+ dump = False
+ conf = pyjsl.conf.Conf()
+ profile_func = profile_disabled
+ for opt, val in opts:
+ if opt in ('-h', '--help'):
+ usage()
+ sys.exit()
+ if opt in ('--dump',):
+ dump = True
+ if opt in ('-t', '--test'):
+ profile_func(run_tests)
+ if opt in ('--unittest',):
+ unittest.main(pyjsl.parse, argv=sys.argv[:1])
+ if opt in ('--profile',):
+ profile_func = profile_enabled
+ if opt in ('--conf',):
+ conf.loadfile(val)
+
+ paths = []
+ for recurse, path in conf['paths']:
+ paths.extend(_resolve_paths(path, recurse))
+ for arg in args:
+ paths.extend(_resolve_paths(arg, False))
+ if dump:
+ profile_func(_dump, paths)
+ else:
+ profile_func(_lint, paths, conf)
+
+ if _lint_results['errors']:
+ sys.exit(3)
+ if _lint_results['warnings']:
+ sys.exit(1)
+
Property changes on: trunk/jsl.py
___________________________________________________________________
Name: svn:executable
+ *
Property changes on: trunk/pyjsl
___________________________________________________________________
Name: svn:ignore
+ *.pyc
Added: trunk/pyjsl/__init__.py
===================================================================
Added: trunk/pyjsl/conf.py
===================================================================
--- trunk/pyjsl/conf.py (rev 0)
+++ trunk/pyjsl/conf.py 2008-03-01 17:21:01 UTC (rev 147)
@@ -0,0 +1,134 @@
+import os
+
+import warnings
+
+class ConfError(Exception):
+ def __init__(self, error):
+ Exception.__init__(error)
+ self.lineno = None
+ self.path = None
+
+class Setting():
+ wants_parm = False
+ wants_dir = False
+
+class BooleanSetting(Setting):
+ wants_parm = False
+ def __init__(self, default):
+ self.value = default
+ def load(self, enabled):
+ self.value = enabled
+
+class StringSetting(Setting):
+ wants_parm = True
+ def __init__(self, default):
+ self.value = default
+ def load(self, enabled, parm):
+ if not enabled:
+ raise ConfError, 'Expected +.'
+ self.value = parm
+
+class DeclareSetting(Setting):
+ wants_parm = True
+ def __init__(self):
+ self.value = []
+ def load(self, enabled, parm):
+ if not enabled:
+ raise ConfError, 'Expected +.'
+ self.value.append(parm)
+
+class ProcessSetting(Setting):
+ wants_parm = True
+ wants_dir = True
+ def __init__(self, recurse_setting):
+ self.value = []
+ self._recurse = recurse_setting
+ def load(self, enabled, parm, dir):
+ if dir:
+ parm = os.path.join(dir, parm)
+ self.value.append((self._recurse.value, parm))
+
+class Conf():
+ def __init__(self):
+ recurse = BooleanSetting(False)
+ self._settings = {
+ 'recurse': recurse,
+ 'show_context': BooleanSetting(False),
+ 'output-format': StringSetting('TODO'),
+ 'lambda_assign_requires_semicolon': BooleanSetting(False),
+ 'legacy_control_comments': BooleanSetting(True),
+ 'jscript_function_extensions': BooleanSetting(False),
+ 'always_use_option_explicit': BooleanSetting(False),
+ 'define': DeclareSetting(),
+ 'context': BooleanSetting(False),
+ 'process': ProcessSetting(recurse),
+ # SpiderMonkey warnings
+ 'no_return_value': BooleanSetting(True),
+ 'equal_as_assign': BooleanSetting(True),
+ 'anon_no_return_value': BooleanSetting(True)
+ }
+ for klass in warnings.klasses:
+ self._settings[klass.__name__] = BooleanSetting(True)
+ self.loadline('-block_without_braces')
+
+ def loadfile(self, path):
+ path = os.path.abspath(path)
+ conf = open(path, 'r').read()
+ try:
+ self.loadtext(conf, dir=os.path.dirname(path))
+ except ConfError, error:
+ error.path = path
+ raise
+
+ def loadtext(self, conf, dir=None):
+ lines = conf.splitlines()
+ for lineno in range(0, len(lines)):
+ try:
+ self.loadline(lines[lineno], dir)
+ except ConfError, error:
+ error.lineno = lineno
+ raise
+
+ def loadline(self, line, dir=None):
+ assert not '\r' in line
+ assert not '\n' in line
+
+ # Allow comments
+ line = line.partition('#')[0]
+ line = line.rstrip()
+ if not line:
+ return
+
+ # Parse the +/-
+ if line.startswith('+'):
+ enabled = True
+ elif line.startswith('-'):
+ enabled = False
+ else:
+ raise ConfError, 'Expected + or -.'
+ line = line[1:]
+
+ # Parse the key/parms
+ name = line.split()[0].lower()
+ parm = line[len(name):].lstrip()
+
+ # Load the setting
+ setting = self._settings[name]
+ args = {
+ 'enabled': enabled
+ }
+ if setting.wants_parm:
+ args['parm'] = parm
+ elif parm:
+ raise ConfError, 'The %s setting does not expect a parameter.' % name
+ if setting.wants_dir:
+ args['dir'] = dir
+ setting.load(**args)
+
+ def __getitem__(self, name):
+ if name == 'paths':
+ name = 'process'
+ elif name == 'declarations':
+ name = 'define'
+ return self._settings[name].value
+
Added: trunk/pyjsl/lint.py
===================================================================
--- trunk/pyjsl/lint.py (rev 0)
+++ trunk/pyjsl/lint.py 2008-03-01 17:21:01 UTC (rev 147)
@@ -0,0 +1,288 @@
+#!/usr/bin/python
+import os.path
+import re
+
+import conf
+import parse
+import visitation
+import warnings
+import util
+
+_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',
+ 'eval', 'NaN', 'Infinity',
+ 'escape', 'unescape', 'uneval',
+ 'decodeURI', 'encodeURI', 'decodeURIComponent', 'encodeURIComponent',
+ 'Function', 'Object',
+ 'Error', 'InternalError', 'EvalError', 'RangeError', 'ReferenceError',
+ 'SyntaxError', 'TypeError', 'URIError',
+ 'arguments', 'undefined'
+])
+
+_identifier = re.compile('^[A-Za-z_$][A-Za-z0-9_$]*$')
+
+def _find_function(node):
+ while node and node.kind != 'function':
+ node = node.parent
+ return node
+
+def _find_functions(node):
+ functions = []
+ while node:
+ if node.kind == 'function':
+ functions.append(node)
+ node = node.parent
+ return functions
+
+def _parse_control_comment(comment):
+ """ Returns None or (keyword, parms) """
+ if comment.atom.lower().startswith('jsl:'):
+ control_comment = comment.atom[4:]
+ elif comment.atom.startswith('@') and comment.atom.endswith('@'):
+ control_comment = comment.atom[1:-1]
+ else:
+ return None
+
+ control_comments = {
+ 'ignoreall': (False),
+ 'ignore': (False),
+ 'end': (False),
+ 'option explicit': (False),
+ 'import': (True),
+ 'fallthru': (False),
+ 'pass': (False),
+ 'declare': (True)
+ }
+ if control_comment.lower() in control_comments:
+ keyword = control_comment.lower()
+ else:
+ keyword = control_comment.lower().split()[0]
+
+ parms = control_comment[len(keyword):].strip()
+ return (comment, keyword, parms)
+
+class Scope():
+ def __init__(self, node):
+ self._is_with_scope = node.kind == 'with'
+ self._parent = None
+ self._kids = []
+ self._identifiers = {}
+ self._references = []
+ self._node = node
+ def add_scope(self, node):
+ self._kids.append(Scope(node))
+ self._kids[-1]._parent = self
+ if self._is_with_scope:
+ self._kids[-1]._is_with_scope = True
+ return self._kids[-1]
+ def add_declaration(self, name, node):
+ if not self._is_with_scope:
+ self._identifiers[name] = node
+ def add_reference(self, name, node):
+ if not self._is_with_scope:
+ self._references.append((name, node))
+ def get_identifier(self, name):
+ if name in self._identifiers:
+ return self._identifiers[name]
+ else:
+ return None
+ def get_identifiers(self):
+ "returns a list of names"
+ return self._identifiers.keys()
+ def resolve_identifier(self, name):
+ if name in self._identifiers:
+ return self, self._identifiers[name]
+ if self._parent:
+ return self._parent.resolve_identifier(name)
+ return None
+ def get_undeclared_identifiers(self):
+ identifiers = []
+ for child in self._kids:
+ identifiers += child.get_undeclared_identifiers()
+ for name, node in self._references:
+ if not self.resolve_identifier(name):
+ identifiers.append(node)
+ return identifiers
+ def find_scope(self, node):
+ for kid in self._kids:
+ scope = kid.find_scope(node)
+ if scope:
+ return scope
+
+ # Always add it to the outer scope.
+ if not self._parent or \
+ (node.start_pos() >= self._node.start_pos() and \
+ node.end_pos() <= self._node.end_pos()):
+ return self
+
+ return None
+
+def lint_files(paths, lint_error, conf=conf.Conf()):
+ def lint_file(path):
+ def import_script(import_path):
+ import_path = os.path.join(os.path.dirname(path), import_path)
+ return lint_file(import_path)
+ def _lint_error(*args):
+ return lint_error(normpath, *args)
+
+ normpath = util.normpath(path)
+ if not normpath in lint_cache:
+ lint_cache[normpath] = {}
+ script = util.readfile(path)
+ print normpath
+ _lint_script(script, lint_cache[normpath], _lint_error, conf, import_script)
+ return lint_cache[normpath]
+
+ lint_cache = {}
+ for path in paths:
+ lint_file(path)
+
+def _lint_script(script, script_cache, lint_error, conf, import_callback):
+ def parse_error(row, col, msg):
+ if not msg in ('redeclared_var', 'var_hides_arg'):
+ parse_errors.append((parse.NodePos(row, col), msg))
+
+ def report(node, errname):
+ _report(node.start_pos(), errname, True)
+
+ def _report(pos, errname, require_key):
+ try:
+ if not conf[errname]:
+ return
+ except KeyError, err:
+ if require_key:
+ raise
+
+ for start, end in ignores:
+ if pos >= start and pos <= end:
+ return
+
+ return lint_error(pos.line, pos.col, errname)
+
+ parse_errors = []
+ root, comments = parse.parse(script, parse_error)
+ ignores = []
+ start_ignore = None
+ declares = []
+ import_paths = []
+ for comment in comments:
+ cc = _parse_control_comment(comment)
+ if cc:
+ node, keyword, parms = cc
+ if keyword == 'declare':
+ if not _identifier.match(parms):
+ report(node, 'jsl_cc_not_understood')
+ else:
+ declares.append((parms, node))
+ elif keyword == 'ignore':
+ if start_ignore:
+ report(node, 'mismatch_ctrl_comments')
+ else:
+ start_ignore = node
+ elif keyword == 'end':
+ if start_ignore:
+ ignores.append((start_ignore.start_pos(), node.end_pos()))
+ start_ignore = None
+ else:
+ report(node, 'mismatch_ctrl_comments')
+ elif keyword == 'import':
+ if not parms:
+ report(node, 'jsl_cc_not_understood')
+ else:
+ import_paths.append(parms)
+ else:
+ if comment.opcode == 'c_comment':
+ if '/*' in comment.atom or comment.atom.endswith('/'):
+ report(comment, 'nested_comment')
+ if comment.atom.lower().startswith('jsl:'):
+ report(comment, 'jsl_cc_not_understood')
+ elif comment.atom.startswith('@'):
+ report(comment, 'legacy_cc_not_understood')
+ if start_ignore:
+ report(start_ignore, 'mismatch_ctrl_comments')
+
+ # Wait to report parse errors until loading jsl:ignore directives.
+ for pos, msg in parse_errors:
+ _report(pos, msg, False)
+
+ visitors = visitation.make_visitors(warnings.klasses)
+
+ assert not script_cache
+ imports = script_cache['imports'] = set()
+ scope = script_cache['scope'] = Scope(root)
+
+ # kickoff!
+ _lint_node(root, visitors, report, scope)
+
+ # Process imports by copying global declarations into the universal scope.
+ imports |= set(conf['declarations'])
+ imports |= _globals
+ for path in import_paths:
+ cache = import_callback(path)
+ imports |= cache['imports']
+ imports |= set(cache['scope'].get_identifiers())
+
+ for name, node in declares:
+ declare_scope = scope.find_scope(node)
+ if declare_scope.get_identifier(name):
+ report(node, 'redeclared_var')
+ else:
+ declare_scope.add_declaration(name, node)
+
+ for node in scope.get_undeclared_identifiers():
+ if not node.atom in imports:
+ report(node, 'undeclared_identifier')
+
+def _lint_node(node, visitors, report, scope):
+
+ def warn_or_declare(name, node):
+ other = scope.get_identifier(name)
+ if other and other.kind == 'function' and name in other.fn_args:
+ report(node, 'var_hides_arg')
+ elif other:
+ report(node, 'redeclared_var')
+ else:
+ scope.add_declaration(name, node)
+
+ # Let the visitors warn.
+ for kind in (node.kind, '%s:%s' % (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':
+ pass # left side of object literal
+ elif node.parent.kind == 'catch':
+ scope.add_declaration(node.atom, node)
+ else:
+ scope.add_reference(node.atom, node)
+
+ # Push function identifiers
+ if node.kind == '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':
+ scope = scope.add_scope(node)
+ elif node.kind == 'with':
+ scope = scope.add_scope(node)
+
+ if node.parent and node.parent.kind == 'var':
+ warn_or_declare(node.atom, node)
+
+ for child in node.kids:
+ if child:
+ _lint_node(child, visitors, report, scope)
+
Added: trunk/pyjsl/parse.py
===================================================================
--- trunk/pyjsl/parse.py (rev 0)
+++ trunk/pyjsl/parse.py 2008-03-01 17:21:01 UTC (rev 147)
@@ -0,0 +1,336 @@
+#!/usr/bin/python
+""" Parses a script into nodes. """
+import bisect
+import re
+import unittest
+
+import pyspidermonkey
+
+class NodePos():
+ def __init__(self, line, col):
+ self.line = line
+ self.col = col
+ def __cmp__(self, other):
+ if self.line < other.line:
+ return -1
+ if self.line > other.line:
+ return 1
+ if self.col < other.col:
+ return -1
+ if self.col > other.col:
+ return 1
+ return 0
+ def __repr__(self):
+ return '(line %i, col %i)' % (self.line+1, self.col+1)
+
+class NodePositions():
+ " Given a string, allows [x] lookups for NodePos line and column numbers."
+ def __init__(self, text):
+ # Find the length of each line and incrementally sum all of the lengths
+ # to determine the ending position of each line.
+ self._lines = text.splitlines(True)
+ lines = [0] + [len(x) for x in self._lines]
+ for x in range(1, len(lines)):
+ lines[x] += lines[x-1]
+ self._line_offsets = lines
+ def from_offset(self, offset):
+ line = bisect.bisect(self._line_offsets, offset)-1
+ col = offset - self._line_offsets[line]
+ return NodePos(line, col)
+ def to_offset(self, pos):
+ offset = self._line_offsets[pos.line] + pos.col
+ assert offset <= self._line_offsets[pos.line+1] # out-of-bounds col num
+ return offset
+ def text(self, start, end):
+ assert start <= end
+ # Trim the ending first in case it's a single line.
+ lines = self._lines[start.line:end.line+1]
+ lines[-1] = lines[-1][:end.col+1]
+ lines[0] = lines[0][start.col:]
+ return ''.join(lines)
+
+class NodeRanges():
+ def __init__(self):
+ self._offsets = []
+ def add(self, start, end):
+ i = bisect.bisect_left(self._offsets, start)
+ if i % 2 == 1:
+ i -= 1
+ start = self._offsets[i]
+
+ end = end + 1
+ j = bisect.bisect_left(self._offsets, end)
+ if j % 2 == 1:
+ end = self._offsets[j]
+ j += 1
+
+ self._offsets[i:j] = [start,end]
+ def has(self, pos):
+ return bisect.bisect_right(self._offsets, pos) % 2 == 1
+
+class _Node():
+ def __init__(self, kwargs):
+ 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()
+ self.opcode = kwargs['opcode']
+ self.kids = tuple([_to_node(kid) for kid in kwargs['kids']])
+ for kid in self.kids:
+ if kid:
+ kid.parent = self
+ if 'atom' in kwargs:
+ self.atom = kwargs['atom']
+ if 'dval' in kwargs:
+ self.dval = kwargs['dval']
+ if 'fn_name' in kwargs:
+ self.fn_name = kwargs['fn_name']
+ if 'fn_args' in kwargs:
+ self.fn_args = kwargs['fn_args']
+ if 'end_comma' in kwargs:
+ self.end_comma = kwargs['end_comma']
+ self.args = kwargs
+ self.node_index = kwargs['node_index']
+ self.parent = None
+ self.start_line = kwargs['start_row']
+ self._start_pos = None
+ self._end_pos = None
+
+ def add_child(self, node):
+ if node:
+ node.node_index = len(self.kids)
+ node.parent = self
+ self.kids.append(node)
+
+ def start_pos(self):
+ self._start_pos = self._start_pos or \
+ NodePos(self.args['start_row'], self.args['start_col'])
+ return self._start_pos
+
+ def end_pos(self):
+ self._end_pos = self._end_pos or \
+ NodePos(self.args['end_row'], self.args['end_col'])
+ return self._end_pos
+
+ def __repr__(self):
+ kind = self.kind
+ if not kind:
+ kind = '(none)'
+ return '%s>%s' % (kind, str(self.kids))
+
+ def is_equivalent(self, other, are_functions_equiv=False):
+ if not other:
+ return False
+
+ # Bail out for functions
+ if not are_functions_equiv:
+ if self.kind == 'function':
+ return False
+ if self.kind == 'lp' and self.opcode == 'call':
+ return False
+
+ if self.kind != other.kind:
+ return False
+ if self.opcode != other.opcode:
+ return False
+
+ # Check atoms on names, properties, and string constants
+ if self.kind in ('name', 'dot', 'string') and self.atom != other.atom:
+ return False
+
+ # Check values on numbers
+ if self.kind == 'number' and self.dval != other.dval:
+ return False
+
+ # Compare child nodes
+ if len(self.kids) != len(other.kids):
+ return False
+ for i in range(0, len(self.kids)):
+ # Watch for dead nodes
+ if not self.kids[i]:
+ if not other.kids[i]: return True
+ else: return False
+ if not self.kids[i].is_equivalent(other.kids[i]):
+ return False
+
+ return True
+
+def _parse_comments(script, root, node_positions, ignore_ranges):
+ pos = 0
+ single_line_re = r"//[^\r\n]*"
+ multi_line_re = r"/\*(.*?)\*/"
+ full_re = "(%s)|(%s)" % (single_line_re, multi_line_re)
+ comment_re = re.compile(full_re, re.DOTALL)
+
+ comments = []
+ while True:
+ match = comment_re.search(script, pos)
+ if not match:
+ return comments
+
+ # Get the comment text
+ comment_text = script[match.start():match.end()]
+ if comment_text.startswith('/*'):
+ comment_text = comment_text[2:-2]
+ opcode = 'JSOP_C_COMMENT'
+ else:
+ comment_text = comment_text[2:]
+ opcode = 'JSOP_CPP_COMMENT'
+
+ start_offset = match.start()+1
+ end_offset = match.end()
+
+ # Make sure it doesn't start in a string or regexp
+ if not ignore_ranges.has(start_offset):
+ start_pos = node_positions.from_offset(start_offset)
+ end_pos = node_positions.from_offset(end_offset)
+ kwargs = {
+ 'type': 'COMMENT',
+ 'atom': comment_text,
+ 'opcode': opcode,
+ 'start_row': start_pos.line,
+ 'start_col': start_pos.col,
+ 'end_row': end_pos.line,
+ 'end_col': end_pos.col,
+ 'kids': [],
+ 'node_index': None
+ }
+ comment_node = _Node(kwargs)
+ comments.append(comment_node)
+ pos = match.end()
+ else:
+ pos = match.start()+1
+
+def parse(script, error_callback):
+ def _wrapped_callback(line, col, msg):
+ assert msg.startswith('JSMSG_')
+ msg = msg[6:].lower()
+ error_callback(line, col, msg)
+
+ positions = NodePositions(script)
+
+ roots = []
+ nodes = []
+ comment_ignore_ranges = NodeRanges()
+ def process(node):
+ if node.kind == 'number':
+ node.atom = positions.text(node.start_pos(), node.end_pos())
+ elif node.kind == 'string' or \
+ (node.kind == 'object' and node.opcode == 'regexp'):
+ start_offset = positions.to_offset(node.start_pos())
+ end_offset = positions.to_offset(node.end_pos())
+ comment_ignore_ranges.add(start_offset, end_offset)
+ for kid in node.kids:
+ if kid:
+ process(kid)
+ def pop():
+ nodes.pop()
+
+ roots = pyspidermonkey.traverse(script, _wrapped_callback)
+ assert len(roots) == 1
+ root_node = _Node(roots[0])
+ process(root_node)
+
+ comments = _parse_comments(script, root_node, positions, comment_ignore_ranges)
+ return root_node, comments
+
+def _dump_node(node, depth=0):
+ print '. '*depth,
+ if node is None:
+ print '(none)'
+ else:
+ print node.kind, '\t', node.args
+ for node in node.kids:
+ _dump_node(node, depth+1)
+
+def dump_tree(script):
+ def error_callback(line, col, msg):
+ print '(%i, %i): %s', (line, col, msg)
+ node, comments = parse(script, error_callback)
+ _dump_node(node)
+
+class TestComments(unittest.TestCase):
+ def _test(self, script, expected_comments):
+ root, comments = parse(script, lambda line, col, msg: None)
+ encountered_comments = [node.atom for node in comments]
+ self.assertEquals(encountered_comments, list(expected_comments))
+ def testSimpleComments(self):
+ self._test('re = /\//g', ())
+ self._test('re = /\///g', ())
+ self._test('re = /\////g', ('g',))
+ def testCComments(self):
+ self._test('/*a*//*b*/', ('a', 'b'))
+ self._test('/*a\r\na*//*b\r\nb*/', ('a\r\na', 'b\r\nb'))
+ self._test('a//*b*/c', ('*b*/c',))
+ self._test('a///*b*/c', ('/*b*/c',))
+ self._test('a/*//*/;', ('//',))
+ self._test('a/*b*/+/*c*/d', ('b', 'c'))
+
+class TestNodePositions(unittest.TestCase):
+ def _test(self, text, expected_lines, expected_cols):
+ # Get a NodePos list
+ positions = NodePositions(text)
+ positions = [positions.from_offset(i) for i in range(0, len(text))]
+ encountered_lines = ''.join([str(x.line) for x in positions])
+ encountered_cols = ''.join([str(x.col) for x in positions])
+ self.assertEquals(encountered_lines, expected_lines.replace(' ', ''))
+ self.assertEquals(encountered_cols, expected_cols.replace(' ', ''))
+ def testSimple(self):
+ self._test(
+ 'abc\r\ndef\nghi\n\nj',
+ '0000 0 1111 2222 3 4',
+ '0123 4 0123 0123 0 0'
+ )
+ self._test(
+ '\rabc',
+ '0 111',
+ '0 012'
+ )
+ def testText(self):
+ pos = NodePositions('abc\r\ndef\n\nghi')
+ self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 0)), 'a')
+ self.assertEquals(pos.text(NodePos(0, 0), NodePos(0, 2)), 'abc')
+ self.assertEquals(pos.text(NodePos(0, 2), NodePos(1, 2)), 'c\r\ndef')
+ def testOffset(self):
+ pos = NodePositions('abc\r\ndef\n\nghi')
+ self.assertEquals(pos.to_offset(NodePos(0, 2)), 2)
+ self.assertEquals(pos.to_offset(NodePos(1, 0)), 5)
+ self.assertEquals(pos.to_offset(NodePos(3, 1)), 11)
+
+class TestNodeRanges(unittest.TestCase):
+ def testAdd(self):
+ r = NodeRanges()
+ r.add(5, 10)
+ self.assertEquals(r._offsets, [5,11])
+ r.add(15, 20)
+ self.assertEquals(r._offsets, [5,11,15,21])
+ r.add(21,22)
+ self.assertEquals(r._offsets, [5,11,15,23])
+ r.add(4,5)
+ self.assertEquals(r._offsets, [4,11,15,23])
+ r.add(9,11)
+ self.assertEquals(r._offsets, [4,12,15,23])
+ r.add(10,20)
+ self.assertEquals(r._offsets, [4,23])
+ r.add(4,22)
+ self.assertEquals(r._offsets, [4,23])
+ r.add(30,30)
+ self.assertEquals(r._offsets, [4,23,30,31])
+ def testHas(self):
+ r = NodeRanges()
+ r.add(5, 10)
+ r.add(15, 15)
+ assert not r.has(4)
+ assert r.has(5)
+ assert r.has(6)
+ assert r.has(9)
+ assert r.has(10)
+ assert not r.has(14)
+ assert r.has(15)
+ assert not r.has(16)
+if __name__ == '__main__':
+ unittest.main()
+
Added: trunk/pyjsl/util.py
===================================================================
--- trunk/pyjsl/util.py (rev 0)
+++ trunk/pyjsl/util.py 2008-03-01 17:21:01 UTC (rev 147)
@@ -0,0 +1,16 @@
+import codecs
+import os.path
+
+def readfile(path):
+ file = codecs.open(path, 'r', 'utf-8')
+ contents = file.read()
+ if contents[0] == unicode(codecs.BOM_UTF8, 'utf8'):
+ contents = contents[1:]
+ return contents
+
+def normpath(path):
+ path = os.path.abspath(path)
+ path = os.path.normcase(path)
+ path = os.path.normpath(path)
+ return path
+
Added: trunk/pyjsl/visitation.py
===================================================================
--- trunk/pyjsl/visitation.py (rev 0)
+++ trunk/pyjsl/visitation.py 2008-03-01 17:21:01 UTC (rev 147)
@@ -0,0 +1,35 @@
+""" This is an abstract module for visiting specific nodes. This is useed to
+traverse the tree to generate warnings.
+"""
+
+def visit(*args):
+ """ This decorator is used to indicate which nodes the function should
+ examine. The function should accept (self, node) and return the relevant
+ node or None. """
+ def _decorate(fn):
+ fn._visit_nodes = args
+ return fn
+ return _decorate
+
+def make_visitors(klasses):
+ """ Searches klasses for all member functions decorated with @visit and
+ returns a dictionary that maps from node type to visitor function. """
+ visitors = {}
+
+ # Intantiate an instance of each class
+ for klass in klasses:
+ if klass.__name__.lower() != klass.__name__:
+ raise ValueError, 'class names must be lowercase'
+ if not klass.__doc__:
+ raise ValueError, 'missing docstring on class'
+
+ # Look for functions with the "_visit_nodes" property.
+ visitor = klass()
+ for func in [getattr(visitor, name) for name in dir(visitor)]:
+ for node_kind in getattr(func, '_visit_nodes', ()):
+ # Map from node_kind to the function
+ if not node_kind in visitors:
+ visitors[node_kind] = []
+ visitors[node_kind].append(func)
+ return visitors
+
Added: trunk/pyjsl/warnings.py
===================================================================
--- trunk/pyjsl/warnings.py (rev 0)
+++ trunk/pyjsl/warnings.py 2008-03-01 17:21:01 UTC (rev 147)
@@ -0,0 +1,475 @@
+""" This module contains all the warnings. To add a new warning, define a
+class. Its name should be in lowercase and words should be separated by
+underscores. Its docstring should be the warning message.
+
+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'
+format. To report a warning, the function should return the node causing
+the warning.
+
+For example:
+
+ class warning_name:
+ 'questionable JavaScript coding style'
+ @lookat('nodekind', 'nodekind:opcode')
+ def _lint(self, node):
+ if questionable:
+ return node
+"""
+import re
+import sys
+import types
+
+from visitation import visit as lookat
+# 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':
+ return node.node_index
+ return None
+
+def _get_exit_points(node):
+ if node.kind == 'lc':
+ # Only if the last child contains it
+ exit_points = set([None])
+ for kid in node.kids:
+ # "None" is only a valid exit point for the last statement.
+ if None in exit_points:
+ exit_points.remove(None)
+ if kid:
+ exit_points |= _get_exit_points(kid)
+ elif node.kind == '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':
+ 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 == 'default'
+ switch_has_final_fallthru = None in case_exit_points
+ exit_points |= case_exit_points
+
+ # Correct the "None" exit point.
+ exit_points.remove(None)
+
+ # Check if the switch contained any break
+ if 'break' in exit_points:
+ exit_points.remove('break')
+ exit_points.add(None)
+
+ # 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 == 'break':
+ exit_points = set(['break'])
+ elif node.kind == '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':
+ try_, catch_, finally_ = node.kids
+
+ exit_points = _get_exit_points(try_) | _get_exit_points(catch_)
+ if finally_:
+ # Always if the finally has an exit point
+ if None in exit_points:
+ exit_points.remove(None)
+ exit_points |= _get_exit_points(finally_)
+ else:
+ exit_points = set([None])
+
+ return exit_points
+
+class comparison_type_conv:
+ 'comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)'
+ @lookat('eqop: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'):
+ return False
+ if node.kind == 'number' and not node.dval:
+ return False
+ if node.kind == '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')
+ def _lint(self, node):
+ siblings = node.parent.kids
+ if node.node_index != len(siblings)-1:
+ return siblings[node.node_index+1]
+
+class duplicate_case_in_switch:
+ 'duplicate case in switch statement'
+ @lookat('case')
+ def _lint(self, 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 == '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')
+ def _lint(self, node):
+ value, cases = node.kids
+ for case in cases.kids:
+ if case.kind == 'default':
+ return
+ return node
+
+class with_statement:
+ 'with statement hides undeclared variables; use temporary variable instead'
+ @lookat('with')
+ def _lint(self, node):
+ return node
+
+class useless_comparison:
+ 'useless comparison; comparing identical expressions'
+ @lookat('eqop','relop')
+ def _lint(self, node):
+ lvalue, rvalue = node.kids
+ if lvalue.is_equivalent(rvalue):
+ return node
+
+class use_of_label:
+ 'use of label'
+ @lookat('colon:name')
+ def _lint(self, node):
+ return node
+
+class meaningless_block:
+ 'meaningless block; curly braces have no impact'
+ @lookat('lc')
+ def _lint(self, node):
+ if node.parent and node.parent.kind == 'lc':
+ return node
+
+class misplaced_regex:
+ 'regular expressions should be preceded by a left parenthesis, assignment, colon, or comma'
+ @lookat('object:regexp')
+ def _lint(self, node):
+ if node.parent.kind == 'name' and node.parent.opcode == 'setname':
+ return # Allow in var statements
+ if node.parent.kind == 'assign' and node.parent.opcode == 'nop':
+ return # Allow in assigns
+ if node.parent.kind == 'colon' and node.parent.parent.kind == 'rc':
+ return # Allow in object literals
+ if node.parent.kind == 'lp' and node.parent.opcode == 'call':
+ return # Allow in parameters
+ if node.parent.kind == 'dot' and node.parent.opcode == 'getprop':
+ return # Allow in /re/.property
+ if node.parent.kind == 'return':
+ return # Allow for return values
+ return node
+
+class assign_to_function_call:
+ 'assignment to a function call'
+ @lookat('assign')
+ def _lint(self, node):
+ if node.kids[0].kind == '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')
+ def _lint(self, 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 == 'lc':
+ return
+ # Else is only ambiguous in the first branch of an if statement.
+ if tmp.parent.kind == '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')
+ def _lint(self, node):
+ if node.kids[1].kind != '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')
+ @lookat(*_block_nodes)
+ def _lint(self, node):
+ # Ignore "else if"
+ if node.kind == 'if' and node.node_index == 2 and node.parent.kind == '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'.)
+ 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')
+ def _lint(self, node):
+ if node.parent.kind == 'semi':
+ return None
+
+ # Allow within the third part of the "for"
+ tmp = node
+ while tmp and tmp.parent and tmp.parent.kind == 'comma':
+ tmp = tmp.parent
+ if tmp and tmp.node_index == 2 and \
+ tmp.parent.kind == 'reserved' and \
+ tmp.parent.parent.kind == 'for':
+ return None
+
+ return node
+ def _is_for_ternary_stmt(self, node, branch=None):
+ if node.parent and node.parent.kind == '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'
+
+class comma_separated_stmts:
+ 'multiple statements separated by commas (use semicolons?)'
+ @lookat('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':
+ return
+ return node
+
+class empty_statement:
+ 'empty statement or extra semicolon'
+ @lookat('semi')
+ def _semi(self, node):
+ if not node.kids[0]:
+ return node
+ @lookat('lc')
+ def _lc(self, node):
+ if node.kids:
+ return
+ # Ignore the outermost block.
+ if not node.parent:
+ return
+ # Some empty blocks are meaningful.
+ if node.parent.kind in ('catch', 'case', 'default', 'switch', 'function'):
+ return
+ return node
+
+class missing_break:
+ 'missing break statement'
+ @lookat('case', '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'
+ # Ignore empty case statements
+ if not case_contents.kids:
+ return
+ if None in _get_exit_points(case_contents):
+ return node
+
+class missing_break_for_last_case:
+ 'missing break statement for last case in switch'
+ @lookat('case', 'default')
+ def _lint(self, node):
+ if node.node_index < len(node.parent.kids)-1:
+ return
+ case_contents = node.kids[1]
+ assert case_c...
[truncated message content] |
|
From: <mat...@us...> - 2008-03-01 17:17:52
|
Revision: 146
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=146&view=rev
Author: matthiasmiller
Date: 2008-03-01 09:17:49 -0800 (Sat, 01 Mar 2008)
Log Message:
-----------
copy in a fresh copy of SpiderMonkey
Added Paths:
-----------
trunk/spidermonkey/
Copied: trunk/spidermonkey (from rev 145, vendorsrc/Mozilla.org/js/current)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-01 17:11:12
|
Revision: 145
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=145&view=rev
Author: matthiasmiller
Date: 2008-03-01 09:11:09 -0800 (Sat, 01 Mar 2008)
Log Message:
-----------
move the C version of jsl into a branch
Added Paths:
-----------
branches/cjsl/
branches/cjsl/src/
Removed Paths:
-------------
trunk/src/
Copied: branches/cjsl/src (from rev 144, trunk/src)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-01 17:04:39
|
Revision: 144
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=144&view=rev
Author: matthiasmiller
Date: 2008-03-01 09:04:35 -0800 (Sat, 01 Mar 2008)
Log Message:
-----------
Tag vendorsrc/Mozilla.org/js/current as vendorsrc/Mozilla.org/js/1.7.0.
Added Paths:
-----------
vendorsrc/Mozilla.org/js/1.7.0/
Copied: vendorsrc/Mozilla.org/js/1.7.0 (from rev 143, vendorsrc/Mozilla.org/js/current)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <mat...@us...> - 2008-03-01 17:04:27
|
Revision: 143
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=143&view=rev
Author: matthiasmiller
Date: 2008-03-01 09:04:20 -0800 (Sat, 01 Mar 2008)
Log Message:
-----------
Load js-1.7.0 into vendorsrc/Mozilla.org/js/current.
Modified Paths:
--------------
vendorsrc/Mozilla.org/js/current/src/jsapi.c
vendorsrc/Mozilla.org/js/current/src/jsarray.c
vendorsrc/Mozilla.org/js/current/src/jsemit.c
vendorsrc/Mozilla.org/js/current/src/jsgc.c
vendorsrc/Mozilla.org/js/current/src/jsobj.c
vendorsrc/Mozilla.org/js/current/src/jsopcode.c
vendorsrc/Mozilla.org/js/current/src/jsscript.c
vendorsrc/Mozilla.org/js/current/src/jsxdrapi.h
Added Paths:
-----------
vendorsrc/Mozilla.org/js/current/README
vendorsrc/Mozilla.org/js/current/jsd/
vendorsrc/Mozilla.org/js/current/jsd/.cvsignore
vendorsrc/Mozilla.org/js/current/jsd/CVS/
vendorsrc/Mozilla.org/js/current/jsd/CVS/Entries
vendorsrc/Mozilla.org/js/current/jsd/CVS/Entries.Log
vendorsrc/Mozilla.org/js/current/jsd/CVS/Repository
vendorsrc/Mozilla.org/js/current/jsd/CVS/Root
vendorsrc/Mozilla.org/js/current/jsd/CVS/Tag
vendorsrc/Mozilla.org/js/current/jsd/Makefile.in
vendorsrc/Mozilla.org/js/current/jsd/README
vendorsrc/Mozilla.org/js/current/jsd/idl/
vendorsrc/Mozilla.org/js/current/jsd/idl/.cvsignore
vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/
vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Entries
vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Repository
vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Root
vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Tag
vendorsrc/Mozilla.org/js/current/jsd/idl/Makefile.in
vendorsrc/Mozilla.org/js/current/jsd/idl/jsdIDebuggerService.idl
vendorsrc/Mozilla.org/js/current/jsd/jsd.h
vendorsrc/Mozilla.org/js/current/jsd/jsd.mak
vendorsrc/Mozilla.org/js/current/jsd/jsd.pkg
vendorsrc/Mozilla.org/js/current/jsd/jsd1640.def
vendorsrc/Mozilla.org/js/current/jsd/jsd1640.rc
vendorsrc/Mozilla.org/js/current/jsd/jsd3240.rc
vendorsrc/Mozilla.org/js/current/jsd/jsd_atom.c
vendorsrc/Mozilla.org/js/current/jsd/jsd_high.c
vendorsrc/Mozilla.org/js/current/jsd/jsd_hook.c
vendorsrc/Mozilla.org/js/current/jsd/jsd_java.c
vendorsrc/Mozilla.org/js/current/jsd/jsd_lock.c
vendorsrc/Mozilla.org/js/current/jsd/jsd_lock.h
vendorsrc/Mozilla.org/js/current/jsd/jsd_obj.c
vendorsrc/Mozilla.org/js/current/jsd/jsd_scpt.c
vendorsrc/Mozilla.org/js/current/jsd/jsd_stak.c
vendorsrc/Mozilla.org/js/current/jsd/jsd_step.c
vendorsrc/Mozilla.org/js/current/jsd/jsd_text.c
vendorsrc/Mozilla.org/js/current/jsd/jsd_val.c
vendorsrc/Mozilla.org/js/current/jsd/jsd_xpc.cpp
vendorsrc/Mozilla.org/js/current/jsd/jsd_xpc.h
vendorsrc/Mozilla.org/js/current/jsd/jsdebug.c
vendorsrc/Mozilla.org/js/current/jsd/jsdebug.h
vendorsrc/Mozilla.org/js/current/jsd/jsdshell.mak
vendorsrc/Mozilla.org/js/current/jsd/jsdstubs.c
vendorsrc/Mozilla.org/js/current/jsd/mkshell.bat
vendorsrc/Mozilla.org/js/current/jsd/resource.h
vendorsrc/Mozilla.org/js/current/src/CVS/
vendorsrc/Mozilla.org/js/current/src/CVS/Entries
vendorsrc/Mozilla.org/js/current/src/CVS/Repository
vendorsrc/Mozilla.org/js/current/src/CVS/Root
vendorsrc/Mozilla.org/js/current/src/CVS/Tag
vendorsrc/Mozilla.org/js/current/src/config/CVS/
vendorsrc/Mozilla.org/js/current/src/config/CVS/Entries
vendorsrc/Mozilla.org/js/current/src/config/CVS/Repository
vendorsrc/Mozilla.org/js/current/src/config/CVS/Root
vendorsrc/Mozilla.org/js/current/src/config/CVS/Tag
vendorsrc/Mozilla.org/js/current/src/editline/CVS/
vendorsrc/Mozilla.org/js/current/src/editline/CVS/Entries
vendorsrc/Mozilla.org/js/current/src/editline/CVS/Repository
vendorsrc/Mozilla.org/js/current/src/editline/CVS/Root
vendorsrc/Mozilla.org/js/current/src/editline/CVS/Tag
vendorsrc/Mozilla.org/js/current/src/fdlibm/CVS/
vendorsrc/Mozilla.org/js/current/src/fdlibm/CVS/Entries
vendorsrc/Mozilla.org/js/current/src/fdlibm/CVS/Repository
vendorsrc/Mozilla.org/js/current/src/fdlibm/CVS/Root
vendorsrc/Mozilla.org/js/current/src/fdlibm/CVS/Tag
vendorsrc/Mozilla.org/js/current/src/liveconnect/
vendorsrc/Mozilla.org/js/current/src/liveconnect/.cvsignore
vendorsrc/Mozilla.org/js/current/src/liveconnect/CVS/
vendorsrc/Mozilla.org/js/current/src/liveconnect/CVS/Entries
vendorsrc/Mozilla.org/js/current/src/liveconnect/CVS/Repository
vendorsrc/Mozilla.org/js/current/src/liveconnect/CVS/Root
vendorsrc/Mozilla.org/js/current/src/liveconnect/CVS/Tag
vendorsrc/Mozilla.org/js/current/src/liveconnect/LiveConnect.dsp
vendorsrc/Mozilla.org/js/current/src/liveconnect/LiveConnectShell.dsp
vendorsrc/Mozilla.org/js/current/src/liveconnect/LiveConnectShell.dsw
vendorsrc/Mozilla.org/js/current/src/liveconnect/Makefile.in
vendorsrc/Mozilla.org/js/current/src/liveconnect/Makefile.ref
vendorsrc/Mozilla.org/js/current/src/liveconnect/README.html
vendorsrc/Mozilla.org/js/current/src/liveconnect/_jni/
vendorsrc/Mozilla.org/js/current/src/liveconnect/_jni/CVS/
vendorsrc/Mozilla.org/js/current/src/liveconnect/_jni/CVS/Entries
vendorsrc/Mozilla.org/js/current/src/liveconnect/_jni/CVS/Repository
vendorsrc/Mozilla.org/js/current/src/liveconnect/_jni/CVS/Root
vendorsrc/Mozilla.org/js/current/src/liveconnect/_jni/CVS/Tag
vendorsrc/Mozilla.org/js/current/src/liveconnect/_jni/netscape_javascript_JSException.h
vendorsrc/Mozilla.org/js/current/src/liveconnect/_jni/netscape_javascript_JSObject.h
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/.cvsignore
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/CVS/
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/CVS/Entries
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/CVS/Repository
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/CVS/Root
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/CVS/Tag
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/Makefile.in
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/Makefile.ref
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/CVS/
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/CVS/Entries
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/CVS/Repository
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/CVS/Root
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/CVS/Tag
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/Makefile.ref
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/javascript/
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/javascript/CVS/
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/javascript/CVS/Entries
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/javascript/CVS/Repository
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/javascript/CVS/Root
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/javascript/CVS/Tag
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/javascript/JSException.java
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/javascript/JSObject.java
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/javascript/JSProxy.java
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/javascript/JSRunnable.java
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/javascript/JSUtil.java
vendorsrc/Mozilla.org/js/current/src/liveconnect/classes/netscape/javascript/Makefile.ref
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/AIX4.1.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/AIX4.2.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/AIX4.3.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/CVS/
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/CVS/Entries
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/CVS/Repository
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/CVS/Root
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/CVS/Tag
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/HP-UXB.10.10.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/HP-UXB.10.20.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/HP-UXB.11.00.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/IRIX6.2.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/IRIX6.3.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/IRIX6.5.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/Linux_All.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/OSF1V4.0.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/OSF1V5.0.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/SunOS5.5.1.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/SunOS5.6.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/SunOS5.7.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/SunOS5.8.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/config/WINNT4.0.mk
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj.msg
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_JSObject.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_JavaArray.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_JavaClass.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_JavaMember.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_JavaObject.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_JavaPackage.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_array.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_class.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_convert.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_field.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_hash.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_hash.h
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_method.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_nodl.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_private.h
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_simpleapi.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsj_utils.c
vendorsrc/Mozilla.org/js/current/src/liveconnect/jsjava.h
vendorsrc/Mozilla.org/js/current/src/liveconnect/liveconnect.pkg
vendorsrc/Mozilla.org/js/current/src/liveconnect/netscape_javascript_JSObject.h
vendorsrc/Mozilla.org/js/current/src/liveconnect/nsCLiveconnect.cpp
vendorsrc/Mozilla.org/js/current/src/liveconnect/nsCLiveconnect.h
vendorsrc/Mozilla.org/js/current/src/liveconnect/nsCLiveconnectFactory.cpp
vendorsrc/Mozilla.org/js/current/src/liveconnect/nsCLiveconnectFactory.h
vendorsrc/Mozilla.org/js/current/src/liveconnect/nsILiveconnect.h
vendorsrc/Mozilla.org/js/current/src/liveconnect/nsISecureLiveconnect.h
vendorsrc/Mozilla.org/js/current/src/liveconnect/nsISecurityContext.h
vendorsrc/Mozilla.org/js/current/src/liveconnect/win32.order
Property Changed:
----------------
vendorsrc/Mozilla.org/js/current/src/config/Darwin1.3.mk
vendorsrc/Mozilla.org/js/current/src/config/Darwin1.4.mk
vendorsrc/Mozilla.org/js/current/src/config/Darwin5.2.mk
vendorsrc/Mozilla.org/js/current/src/config/Mac_OS10.0.mk
Added: vendorsrc/Mozilla.org/js/current/README
===================================================================
--- vendorsrc/Mozilla.org/js/current/README (rev 0)
+++ vendorsrc/Mozilla.org/js/current/README 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1,7 @@
+1. The latest release notes for SpiderMonkey can be found at:
+
+ http://www.mozilla.org/js/spidermonkey/release-notes/
+
+
+2. js/jsd contains code for debugging support for the C-based JavaScript engine in js/src.
+
Property changes on: vendorsrc/Mozilla.org/js/current/README
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/.cvsignore
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/.cvsignore (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/.cvsignore 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1 @@
+Makefile
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/.cvsignore
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/CVS/Entries
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/CVS/Entries (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/CVS/Entries 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1,30 @@
+/.cvsignore/1.1/Sat Dec 5 09:02:27 1998//TJS_170
+/Makefile.in/1.26/Tue Apr 5 18:26:06 2005//TJS_170
+/README/3.3/Sun Sep 30 08:52:04 2001//TJS_170
+/jsd.h/3.19.2.1/Fri Jul 7 02:12:01 2006//TJS_170
+/jsd.mak/3.2/Thu Apr 3 22:42:02 2003//TJS_170
+/jsd.pkg/1.2/Wed Jan 7 01:21:43 2004//TJS_170
+/jsd1640.def/3.3/Sun Apr 18 21:57:30 2004//TJS_170
+/jsd1640.rc/3.6/Sun Apr 18 21:57:30 2004//TJS_170
+/jsd3240.rc/3.6/Sun Apr 18 21:57:30 2004//TJS_170
+/jsd_atom.c/3.6/Sun Apr 18 21:57:30 2004//TJS_170
+/jsd_high.c/3.12/Sun Apr 18 21:57:30 2004//TJS_170
+/jsd_hook.c/3.10/Sun Apr 18 21:57:30 2004//TJS_170
+/jsd_java.c/3.8/Thu Jul 7 22:35:38 2005//TJS_170
+/jsd_lock.c/3.8/Sun Apr 18 21:57:30 2004//TJS_170
+/jsd_lock.h/3.7/Sun Apr 18 21:57:30 2004//TJS_170
+/jsd_obj.c/3.8/Sun Apr 18 21:57:30 2004//TJS_170
+/jsd_scpt.c/3.13/Tue Aug 2 15:53:59 2005//TJS_170
+/jsd_stak.c/3.21.20.1/Fri Aug 25 14:02:55 2006//TJS_170
+/jsd_step.c/3.16/Tue Aug 2 18:46:14 2005//TJS_170
+/jsd_text.c/3.8/Sun Apr 18 21:57:30 2004//TJS_170
+/jsd_val.c/3.9.28.1/Fri Jul 7 02:12:01 2006//TJS_170
+/jsd_xpc.cpp/1.72.2.1/Tue Jun 20 15:54:58 2006//TJS_170
+/jsd_xpc.h/1.21/Sun Apr 18 21:57:31 2004//TJS_170
+/jsdebug.c/3.15/Tue Aug 2 15:53:59 2005//TJS_170
+/jsdebug.h/3.19/Tue Aug 2 15:53:59 2005//TJS_170
+/jsdshell.mak/3.2/Thu Apr 3 22:42:02 2003//TJS_170
+/jsdstubs.c/3.8/Thu Jul 7 22:35:38 2005//TJS_170
+/mkshell.bat/3.1/Thu Nov 5 08:57:03 1998//TJS_170
+/resource.h/3.6/Sun Apr 18 21:57:31 2004//TJS_170
+D
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/CVS/Entries
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/CVS/Entries.Log
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/CVS/Entries.Log (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/CVS/Entries.Log 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1,13 @@
+A D/classes////
+A D/corba////
+A D/idl////
+A D/java////
+A D/javawrap////
+A D/jsdb////
+A D/macbuild////
+R D/macbuild////
+R D/jsdb////
+R D/javawrap////
+R D/java////
+R D/corba////
+R D/classes////
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/CVS/Entries.Log
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/CVS/Repository
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/CVS/Repository (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/CVS/Repository 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1 @@
+mozilla/js/jsd
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/CVS/Repository
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/CVS/Root
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/CVS/Root (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/CVS/Root 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1 @@
+:pserver:ano...@cv...:/cvsroot
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/CVS/Root
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/CVS/Tag
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/CVS/Tag (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/CVS/Tag 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1 @@
+NJS_170
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/CVS/Tag
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/Makefile.in
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/Makefile.in (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/Makefile.in 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1,110 @@
+#!gmake
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+
+
+DEPTH = ../..
+topsrcdir = @top_srcdir@
+VPATH = @srcdir@
+srcdir = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = jsdebug
+LIBRARY_NAME = jsd
+FORCE_SHARED_LIB= 1
+ifeq ($(OS_ARCH)$(MOZ_ENABLE_LIBXUL),WINNT)
+LIBRARY_NAME = jsd$(MOZ_BITS)$(VERSION_NUMBER)
+endif
+
+# REQUIRES = java js
+REQUIRES = js
+
+ifndef JSD_STANDALONE
+REQUIRES += \
+ string \
+ xpcom \
+ xpconnect \
+ widget \
+ dom \
+ $(NULL)
+
+PACKAGE_FILE = jsd.pkg
+endif
+
+EXTRA_DSO_LDOPTS += \
+ $(MOZ_COMPONENT_LIBS) \
+ $(MOZ_JS_LIBS) \
+ $(NULL)
+EXPORTS = jsdebug.h
+
+ifdef JS_THREADSAFE
+DEFINES += -DJS_THREADSAFE
+endif
+
+CSRCS = \
+ jsdebug.c \
+ jsd_atom.c \
+ jsd_high.c \
+ jsd_hook.c \
+ jsd_lock.c \
+ jsd_obj.c \
+ jsd_scpt.c \
+ jsd_stak.c \
+ jsd_step.c \
+ jsd_text.c \
+ jsd_val.c \
+ $(NULL)
+
+ifdef JSD_STANDALONE
+DIRS += jsdb
+else
+DIRS += idl
+CPPSRCS = jsd_xpc.cpp
+IS_COMPONENT = 1
+LIBXUL_LIBRARY = 1
+
+ifdef MOZ_ENABLE_LIBXUL
+FORCE_SHARED_LIB=
+MODULE_NAME = JavaScript_Debugger
+endif
+endif
+
+include $(topsrcdir)/config/rules.mk
+
+DEFINES += -DEXPORT_JSD_API
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/Makefile.in
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/README
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/README (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/README 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1,6 @@
+js/jsd contains code for debugging support for the C-based JavaScript engine
+in js/src. jsd_xpc.cpp provides an XPCOM binding for the library.
+
+js/jsd/jsdb is a console debugger using only native code (see README in that
+directory.) This debugger is no longer being actively developed, though it
+should work.
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/README
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/idl/.cvsignore
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/idl/.cvsignore (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/idl/.cvsignore 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1 @@
+Makefile
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/idl/.cvsignore
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Entries
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Entries (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Entries 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1,4 @@
+/.cvsignore/1.1/Fri Jul 6 02:36:12 2001//TJS_170
+/Makefile.in/1.3/Sun Apr 18 21:57:31 2004//TJS_170
+/jsdIDebuggerService.idl/1.32/Tue Aug 2 15:53:59 2005//TJS_170
+D
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Entries
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Repository
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Repository (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Repository 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1 @@
+mozilla/js/jsd/idl
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Repository
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Root
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Root (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Root 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1 @@
+:pserver:ano...@cv...:/cvsroot
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Root
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Tag
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Tag (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Tag 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1 @@
+NJS_170
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/idl/CVS/Tag
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/idl/Makefile.in
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/idl/Makefile.in (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/idl/Makefile.in 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1,52 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = jsdebug
+XPIDL_MODULE = jsdservice
+
+XPIDLSRCS = \
+ jsdIDebuggerService.idl \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
Property changes on: vendorsrc/Mozilla.org/js/current/jsd/idl/Makefile.in
___________________________________________________________________
Name: svn:eol-style
+ native
Added: vendorsrc/Mozilla.org/js/current/jsd/idl/jsdIDebuggerService.idl
===================================================================
--- vendorsrc/Mozilla.org/js/current/jsd/idl/jsdIDebuggerService.idl (rev 0)
+++ vendorsrc/Mozilla.org/js/current/jsd/idl/jsdIDebuggerService.idl 2008-03-01 17:04:20 UTC (rev 143)
@@ -0,0 +1,1255 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Robert Ginda, <rg...@ne...>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+%{ C++
+#include "jsdebug.h"
+#include "nsAString.h"
+%}
+
+[ptr] native JSDContext(JSDContext);
+[ptr] native JSDObject(JSDObject);
+[ptr] native JSDProperty(JSDProperty);
+[ptr] native JSDScript(JSDScript);
+[ptr] native JSDStackFrameInfo(JSDStackFrameInfo);
+[ptr] native JSDThreadState(JSDThreadState);
+[ptr] native JSDValue(JSDValue);
+[ptr] native JSRuntime(JSRuntime);
+[ptr] native JSContext(JSContext);
+
+/* interfaces we declare in this file */
+interface jsdIDebuggerService;
+interface jsdIFilter;
+interface jsdINestCallback;
+interface jsdIFilterEnumerator;
+interface jsdIContextEnumerator;
+interface jsdIScriptEnumerator;
+interface jsdIScriptHook;
+interface jsdIErrorHook;
+interface jsdIExecutionHook;
+interface jsdICallHook;
+interface jsdIEphemeral;
+interface jsdIPC;
+interface jsdIContext;
+interface jsdIStackFrame;
+interface jsdIScript;
+interface jsdIValue;
+interface jsdIObject;
+interface jsdIProperty;
+
+/**
+ * Debugger service. It's not a good idea to have more than one active client of
+ * the debugger service.
+ */
+[scriptable, uuid(9dd9006a-4e5e-4a80-ac3d-007fb7335ca4)]
+interface jsdIDebuggerService : nsISupports
+{
+ /** Internal use only. */
+ [noscript] readonly attribute JSDContext JSDContext;
+
+ /**
+ * Called when an error or warning occurs.
+ */
+ attribute jsdIErrorHook errorHook;
+ /**
+ * Called when a jsdIScript is created or destroyed.
+ */
+ attribute jsdIScriptHook scriptHook;
+ /**
+ * Called when the engine encounters a breakpoint.
+ */
+ attribute jsdIExecutionHook breakpointHook;
+ /**
+ * Called when the engine encounters the debugger keyword.
+ */
+ attribute jsdIExecutionHook debuggerHook;
+ /**
+ * Called when the errorHook returns false.
+ */
+ attribute jsdIExecutionHook debugHook;
+ /**
+ * Called before the next PC is executed.
+ */
+ attribute jsdIExecutionHook interruptHook;
+ /**
+ * Called when an exception is thrown (even if it will be caught.)
+ */
+ attribute jsdIExecutionHook throwHook;
+ /**
+ * Called before and after a toplevel script is evaluated.
+ */
+ attribute jsdICallHook topLevelHook;
+ /**
+ * Called before and after a function is called.
+ */
+ attribute jsdICallHook functionHook;
+
+
+ /**
+ * VERSION_* values must be kept in sync with the JSVersion enumeration in
+ * jspubtd.h.
+ */
+
+ /**
+ * Possible values for jsdIScript::version and jsdIContext::version.
+ */
+ const long VERSION_1_0 = 100;
+ const long VERSION_1_1 = 110;
+ const long VERSION_1_2 = 120;
+ const long VERSION_1_3 = 130;
+ const long VERSION_1_4 = 140;
+ const long VERSION_1_5 = 150;
+ const long VERSION_DEFAULT = 0;
+ const long VERSION_UNKNOWN = -1;
+
+ /**
+ * These flags need to be kept in sync with the context flags defined in
+ * jsdebug.h
+ */
+
+ /**
+ * Link native frames in call stacks.
+ */
+ const unsigned long ENABLE_NATIVE_FRAMES = 0x01;
+ /**
+ * Normally, if a script has a 0 in JSD_SCRIPT_PROFILE_BIT it is included in
+ * profile data, otherwise it is not profiled. Setting the
+ * PROFILE_WHEN_SET flag reverses this convention.
+ */
+ const unsigned long PROFILE_WHEN_SET = 0x02;
+ /**
+ * Normally, when the script in the top frame of a thread state has a 1 in
+ * JSD_SCRIPT_DEBUG_BIT, the execution hook is ignored. Setting the
+ * DEBUG_WHEN_SET flag reverses this convention.
+ */
+ const unsigned long DEBUG_WHEN_SET = 0x04;
+ /**
+ * When this flag is set the internal call hook will collect profile data.
+ */
+ const unsigned long COLLECT_PROFILE_DATA = 0x08;
+ /**
+ * When this flag is set, stack frames that are disabled for debugging
+ * will not appear in the call stack chain.
+ */
+ const unsigned long HIDE_DISABLED_FRAMES = 0x10;
+ /**
+ * When this flag is set, the debugger will only check the
+ * JSD_SCRIPT_DEBUG_BIT on the top (most recent) stack frame. This
+ * makes it possible to stop in an enabled frame which was called from
+ * a stack that contains a disabled frame.
+ *
+ * When this flag is *not* set, any stack that contains a disabled frame
+ * will not be debugged (the execution hook will not be invoked.)
+ *
+ * This only applies when the reason for calling the hook would have
+ * been TYPE_INTERRUPTED or TYPE_THROW. TYPE_BREAKPOINT,
+ * TYPE_DEBUG_REQUESTED, and TYPE_DEBUGGER_KEYWORD always stop, regardless
+ * of this setting, as long as the top frame is not disabled.
+ *
+ * If HIDE_DISABLED_FRAMES is set, this is effectively set as well.
+ */
+ const unsigned long MASK_TOP_FRAME_ONLY = 0x20;
+ /**
+ * When this flag is set, object creation will not be tracked. This will
+ * reduce the performance price you pay by enabling the debugger.
+ */
+ const unsigned long DISABLE_OBJECT_TRACE = 0x40;
+
+ /**
+ * Debugger service flags.
+ */
+ attribute unsigned long flags;
+
+ /**
+ * Major version number of implementation.
+ */
+ readonly attribute unsigned long implementationMajor;
+ /**
+ * Minor version number of implementation.
+ */
+ readonly attribute unsigned long implementationMinor;
+ /**
+ * Free form string identifier for implementation.
+ */
+ readonly attribute string implementationString;
+
+ /**
+ * |true| if the debugger should register an app-start observer in order
+ * to begin collecting debug information when mozilla is launched.
+ */
+ attribute boolean initAtStartup;
+
+ /**
+ * |true| if the debugger service has been turned on. This does not
+ * necessarily mean another app is actively using the service, as the
+ * autostart pref may have turned the service on.
+ */
+ readonly attribute boolean isOn;
+
+ /**
+ * Turn on the debugger. This function should only be called from JavaScript
+ * code. The debugger will be enabled on the runtime the call is made on,
+ * as determined by nsIXPCNativeCallContext.
+ */
+ void on ();
+ /**
+ * Turn on the debugger for a given runtime.
+ *
+ * @param rt The runtime you want to debug. You cannot turn the debugger
+ * on for multiple runtimes.
+ */
+ [noscript] void onForRuntime (in JSRuntime rt);
+ /**
+ * Turn the debugger off. This will invalidate all of your jsdIEphemeral
+ * derived objects, and clear all of your breakpoints. In theory you
+ * should be able to turn the debugger back on at some later time without
+ * any problems.
+ */
+ void off ();
+
+ /**
+ * Peek at the current pause depth of the debugger.
+ *
+ * @return depth Number of pause() calls still waiting to be unPause()d.
+ */
+ readonly attribute unsigned long pauseDepth;
+ /**
+ * Temporarily disable the debugger. Hooks will not be called while the
+ * debugger is paused. Multiple calls to pause will increase the "pause
+ * depth", and equal number of unPause calles must be made to resume
+ * normal debugging.
+ *
+ * @return depth Number of times pause has been called since the debugger
+ * has been unpaused.
+ */
+ unsigned long pause();
+ /**
+ * Undo a pause.
+ *
+ * @return depth The number of remaining pending pause calls.
+ */
+ unsigned long unPause();
+
+ /**
+ * Force the engine to perform garbage collection.
+ */
+ void GC();
+
+ /**
+ * Clear profile data for all scripts.
+ */
+ void clearProfileData();
+
+ /**
+ * Adds an execution hook filter. These filters are consulted each time one
+ * of the jsdIExecutionHooks is about to be called. Filters are matched in
+ * a first in, first compared fashion. The first filter to match determines
+ * whether or not the hook is called. Use swapFilter to reorder existing
+ * filters, and removeFilter to remove them.
+ *
+ * If |filter| is already present this method throws NS_ERROR_INVALID_ARG.
+ *
+ * @param filter Object representing the filter to add.
+ * @param after Insert |filter| after this one. Pass null to insert at
+ * the beginning.
+ */
+ void insertFilter (in jsdIFilter filter, in jsdIFilter after);
+ /**
+ * Same as insertFilter, except always add to the end of the list.
+ */
+ void appendFilter (in jsdIFilter filter);
+ /**
+ * Remove a filter.
+ *
+ * If |filter| is not present this method throws NS_ERROR_INVALID_ARG.
+ *
+ * @param filter Object representing the filter to remove. Must be the exact
+ * object passed to addFilter, not just a new object with the same
+ * properties.
+ */
+ void removeFilter (in jsdIFilter filter);
+ /**
+ * Swap position of two filters.
+ *
+ * If |filter_a| is not present, this method throws NS_ERROR_INVALID_ARG.
+ * If |filter_b| is not present, filter_a is replaced by filter_b.
+ * If |filter_a| == |filter_b|, then filter is refreshed.
+ */
+ void swapFilters (in jsdIFilter filter_a, in jsdIFilter filter_b);
+ /**
+ * Enumerate registered filters. This routine refreshes each filter before
+ * passing them on to the enumeration function. Calling this with a null
+ * |enumerator| is equivalent to jsdIService::refreshFilters.
+ *
+ * @param enumerator jsdIFilterEnumerator instance to be called back for the
+ * enumeration.
+ */
+ void enumerateFilters (in jsdIFilterEnumerator enumerator);
+ /**
+ * Force the debugger to resync its internal filter cache with the
+ * actual values in the jsdIFilter objects. To refresh a single filter
+ * use jsdIService::swapFilters. This method is equivalent to
+ * jsdIService::enumerateFilters with a null enumerator.
+ */
+ void refreshFilters ();
+ /**
+ * Clear the list of filters.
+ */
+ void clearFilters();
+
+ /**
+ * Enumerate all known contexts.
+ */
+ void enumerateContexts (in jsdIContextEnumerator enumerator);
+
+ /**
+ * Enumerate all scripts the debugger knows about. Any scripts created
+ * before you turned the debugger on, or after turning the debugger off
+ * will not be available unless the autostart perf is set.
+ *
+ * @param enumerator jsdIScriptEnumerator instance to be called back for
+ * the enumeration.
+ */
+ void enumerateScripts (in jsdIScriptEnumerator enumerator);
+ /**
+ * Clear all breakpoints in all scripts.
+ */
+ void clearAllBreakpoints ();
+
+ /**
+ * When called from JavaScript, this method returns the jsdIValue wrapper
+ * for the given value. If a wrapper does not exist one will be created.
+ * When called from another language this method returns an xpconnect
+ * defined error code.
+ */
+ jsdIValue wrapValue (/*in jsvalue value*/);
+
+ /* XXX these two routines are candidates for refactoring. The only problem
+ * is that it is not clear where and how they should land.
+ */
+
+ /**
+ * Push a new network queue, and enter a new UI event loop.
+ * @param callback jsdINestCallback instance to be called back after the
+ * network queue has been pushed, but before the
+ * UI loop starts.
+ * @return depth returns the current number of times the event loop has been
+ * nested. your code can use it for sanity checks.
+ */
+ unsigned long enterNestedEventLoop (in jsdINestCallback callback);
+ /**
+ * Exit the current nested event loop after the current iteration completes,
+ * and pop the network event queue.
+ *
+ * @return depth returns the current number of times the event loop has been
+ * nested. your code can use it for sanity checks.
+ */
+ unsigned long exitNestedEventLoop ();
+};
+
+/* callback interfaces */
+
+/**
+ * Object representing a pattern of global object and/or url the debugger should
+ * ignore. The debugger service itself will not modify properties of these
+ * objects.
+ */
+[scriptable, uuid(05593438-1b83-4517-864f-3cea3d37a266)]
+interface jsdIFilter : nsISupports
+{
+ /**
+ * These two bytes of the flags attribute are reserved for interpretation
+ * by the jsdService implementation. You can do what you like with the
+ * remaining flags.
+ */
+ const unsigned long FLAG_RESERVED_MASK = 0xFF;
+ /**
+ * Filters without this flag set are ignored.
+ */
+ const unsigned long FLAG_ENABLED = 0x01;
+ /**
+ * Filters with this flag set are "pass" filters, they allow matching hooks
+ * to continue. Filters without this flag block matching hooks.
+ */
+ const unsigned long FLAG_PASS = 0x02;
+
+ /**
+ * FLAG_* values from above, OR'd together.
+ */
+ attribute unsigned long flags;
+
+ /**
+ * An nsISupports version of the global object to be filtered. A null glob
+ * matches all hooks. This attribute must be QI'able to the
+ * (non-scriptable) nsIScriptGlobalObject interface.
+ *
+ * The jsdIService caches this value internally, to if it changes you must
+ * swap the filter with itself using jsdIService::swapFilters.
+ */
+ attribute nsISupports globalObject;
+
+ /**
+ * String representing the url pattern to be filtered. Supports limited
+ * glob matching, at the beginning and end of the pattern only. For example,
+ * "chrome://venkman*" filters all urls that start with chrome/venkman,
+ * "*.cgi" filters all cgi's, and "http://myserver/utils.js" filters only
+ * the utils.js file on "myserver". A null urlPattern matches all urls.
+ *
+ * The jsdIService caches this value internally, to if it changes you must
+ * swap the filter with itself using jsdIService::swapFilters.
+ */
+ attribute string urlPattern;
+
+ /**
+ * Line number for the start of this filter. Line numbers are one based.
+ * Assigning a 0 to this attribute will tell the debugger to ignore the
+ * entire file.
+ */
+ attribute unsigned long startLine;
+
+ /**
+ * Line number for the end of this filter. Line numbers are one based.
+ * Assigning a 0 to this attribute will tell the debugger to ignore from
+ * |startLine| to the end of the file.
+ */
+ attribute unsigned long endLine;
+};
+
+/**
+ * Pass an instance of one of these to jsdIDebuggerService::enterNestedEventLoop.
+ */
+[scriptable, uuid(88bea60f-9b5d-4b39-b08b-1c3a278782c6)]
+interface jsdINestCallback : nsISupports
+{
+ /**
+ * This method will be called after pre-nesting work has completed, such
+ * as pushing the js context and network event queue, but before the new
+ * event loop starts.
+ */
+ void onNest ();
+};
+
+/**
+ * Pass an instance of one of these to jsdIDebuggerService::enumerateFilters.
+ */
+[scriptable, uuid(54382875-ed12-4f90-9a63-1f0498d0a3f2)]
+interface jsdIFilterEnumerator : nsISupports
+{
+ /**
+ * The enumerateFilter method will be called once for every filter the
+ * debugger knows about.
+ */
+ void enumerateFilter (in jsdIFilter filter);
+};
+
+/**
+ * Pass an instance of one of these to jsdIDebuggerService::enumerateScripts.
+ */
+[scriptable, uuid(4c2f706e-1dd2-11b2-9ebc-85a06e948830)]
+interface jsdIScriptEnumerator : nsISupports
+{
+ /**
+ * The enumerateScript method will be called once for every script the
+ * debugger knows about.
+ */
+ void enumerateScript (in jsdIScript script);
+};
+
+/**
+ * Pass an instance of one of these to jsdIDebuggerService::enumerateContexts.
+ */
+[scriptable, uuid(912e342a-1dd2-11b2-b09f-cf3af38c15f0)]
+interface jsdIContextEnumerator : nsISupports
+{
+ /**
+ * The enumerateContext method will be called once for every context
+ * currently in use.
+ */
+ void enumerateContext (in jsdIContext executionContext);
+};
+
+/**
+ * Set jsdIDebuggerService::scriptHook to an instance of one of these.
+ */
+[scriptable, uuid(ae89a7e2-1dd1-11b2-8c2f-af82086291a5)]
+interface jsdIScriptHook : nsISupports
+{
+ /**
+ * Called when scripts are created.
+ */
+ void onScriptCreated (in jsdIScript script);
+ /**
+ * Called when the JavaScript engine destroys a script. The jsdIScript
+ * object passed in will already be invalidated.
+ */
+ void onScriptDestroyed (in jsdIScript script);
+};
+
+/**
+ * Hook instances of this interface up to the
+ * jsdIDebuggerService::functionHook and toplevelHook properties.
+ */
+[scriptable, uuid(f102caf6-1dd1-11b2-bd43-c1dbacb95a98)]
+interface jsdICallHook : nsISupports
+{
+ /**
+ * TYPE_* values must be kept in sync with the JSD_HOOK_* #defines
+ * in jsdebug.h.
+ */
+
+ /**
+ * Toplevel script is starting.
+ */
+ const unsigned long TYPE_TOPLEVEL_START = 0;
+ /**
+ * Toplevel script has completed.
+ */
+ const unsigned long TYPE_TOPLEVEL_END = 1;
+ /**
+ * Function is being called.
+ */
+ const unsigned long TYPE_FUNCTION_CALL = 2;
+ /**
+ * Function is returning.
+ */
+ const unsigned long TYPE_FUNCTION_RETURN = 3;
+
+ /**
+ * Called before the JavaScript engine executes a top level script or calls
+ * a function.
+ */
+ void onCall (in jsdIStackFrame frame, in unsigned long type);
+};
+
+[scriptable, uuid(b7dd3c1c-1dd1-11b2-83eb-8a857d199e0f)]
+interface jsdIErrorHook : nsISupports
+{
+ /**
+ * REPORT_* values must be kept in sync with JSREPORT_* #defines in
+ * jsapi.h
+ */
+
+ /**
+ * Report is an error.
+ */
+ const unsigned long REPORT_ERROR = 0x00;
+ /**
+ * Report is only a warning.
+ */
+ const unsigned long REPORT_WARNING = 0x01;
+ /**
+ * Report represents an uncaught exception.
+ */
+ const unsigned long REPORT_EXCEPTION = 0x02;
+ /**
+ * Report is due to strict mode.
+ */
+ const unsigned long REPORT_STRICT = 0x04;
+
+ /**
+ * Called when the JavaScript engine encounters an error. Return |true|
+ * to pass the error along, |false| to invoke the debugHook.
+ */
+ boolean onError (in string message, in string fileName,
+ in unsigned long line, in unsigned long pos,
+ in unsigned long flags, in unsigned long errnum,
+ in jsdIValue exc);
+};
+
+/**
+ * Hook instances of this interface up to the
+ * jsdIDebuggerService::breakpointHook, debuggerHook, errorHook, interruptHook,
+ * and throwHook properties.
+ */
+[scriptable, uuid(9a7b6ad0-1dd1-11b2-a789-fcfae96356a2)]
+interface jsdIExecutionHook : nsISupports
+{
+ /**
+ * TYPE_* values must be kept in sync with JSD_HOOK_* #defines in jsdebug.h.
+ */
+
+ /**
+ * Execution stopped because we're in single step mode.
+ */
+ const unsigned long TYPE_INTERRUPTED = 0;
+ /**
+ * Execution stopped by a trap instruction (i.e. breakoint.)
+ */
+ const unsigned long TYPE_BREAKPOINT = 1;
+ /**
+ * Error handler returned an "invoke debugger" value.
+ */
+ const unsigned long TYPE_DEBUG_REQUESTED = 2;
+ /**
+ * Debugger keyword encountered.
+ */
+ const unsigned long TYPE_DEBUGGER_KEYWORD = 3;
+ /**
+ * Exception was thrown.
+ */
+ const unsigned long TYPE_THROW = 4;
+
+ /**
+ * RETURN_* values must be kept in sync with JSD_HOOK_RETURN_* #defines in
+ * jsdebug.h.
+ */
+
+ /**
+ * Indicates unrecoverable error processing the hook. This will cause
+ * the script being executed to be aborted without raising a JavaScript
+ * exception.
+ */
+ const unsigned long RETURN_HOOK_ERROR = 0;
+ /**
+ * Continue processing normally. This is the "do nothing special" return
+ * value for all hook types *except* TYPE_THROW. Returning RETURN_CONTINUE
+ * from TYPE_THROW cause the exception to be ignored. Return
+ * RETURN_CONTINUE_THROW to continue exception processing from TYPE_THROW
+ * hooks.
+ */
+ const unsigned long RETURN_CONTINUE = 1;
+ /**
+ * Same effect as RETURN_HOOK_ERROR.
+ */
+ const unsigned long RETURN_ABORT = 2;
+ /**
+ * Return the value of the |val| parameter.
+ */
+ const unsigned long RETURN_RET_WITH_VAL = 3;
+ /**
+ * Throw the value of the |val| parameter.
+ */
+ const unsigned long RETURN_THROW_WITH_VAL = 4;
+ /**
+ * Continue the current throw.
+ */
+ const unsigned long RETURN_CONTINUE_THROW = 5;
+
+ /**
+ * @param frame A jsdIStackFrame object representing the bottom stack frame.
+ * @param type One of the jsdIExecutionHook::TYPE_ constants.
+ * @param val in - Current exception (if any) when this method is called.
+ * out - If you return RETURN_THROW_WITH_VAL, value to be
+ * thrown.
+ * If you return RETURN_RET_WITH_VAL, value to return.
+ * All other return values, not significant.
+ * @retval One of the jsdIExecutionHook::RETURN_* constants.
+ */
+ unsigned long onExecute (in jsdIStackFrame frame,
+ in unsigned long type, inout jsdIValue val);
+};
+
+/**
+ * Objects which inherit this interface may go away, with (jsdIScript) or
+ * without (all others) notification. These objects are generally wrappers
+ * around JSD structures that go away when you call jsdService::Off().
+ */
+[scriptable, uuid(46f1e23e-1dd2-11b2-9ceb-8285f2e95e69)]
+interface jsdIEphemeral : nsISupports
+{
+ /**
+ * |true| if this object is still valid. If not, many or all of the methods
+ * and/or properties of the inheritor may no longer be callable.
+ */
+ readonly attribute boolean isValid;
+ /**
+ * Mark this instance as invalid.
+ */
+ [noscript] void invalidate();
+};
+
+/* handle objects */
+
+/**
+ * Context object. Only context's which are also nsISupports objects can be
+ * reflected by this interface.
+ */
+[scriptable, uuid(a2dd25a4-1dd1-11b2-bda6-ed525acd4c35)]
+interface jsdIContext : jsdIEphemeral
+{
+ /* Internal use only. */
+ [noscript] readonly attribute JSContext JSContext;
+
+ /**
+ * OPT_* values must be kept in sync with JSOPTION_* #defines in jsapi.h.
+ */
+
+ /**
+ * Strict mode is on.
+ */
+ const long OPT_STRICT = 0x01;
+ /**
+ * Warnings reported as errors.
+ */
+ const long OPT_WERR = 0x02;
+ /**
+ * Makes eval() use the last object on its 'obj' param's scope chain as the
+ * ECMA 'variables object'.
+ */
+ const long OPT_VAROBJFIX = 0x04;
+ /**
+ * Private data for this object is an nsISupports object. Attempting to
+ * alter this bit will result in an NS_ERROR_ILLEGAL_VALUE.
+ */
+ const long OPT_ISUPPORTS = 0x08;
+ /**
+ * OPT_* values above, OR'd together.
+ */
+ attribute unsigned long options;
+
+ /**
+ * Last version set on this context.
+ * Scripts typically select this with the "language" attribute.
+ * See the VERSION_* consts on jsdIDebuggerService.
+ */
+ attribute long version;
+
+ /**
+ * Unique tag among all valid jsdIContext objects, useful as a hash key.
+ */
+ readonly attribute unsigned long tag;
+
+ /**
+ * Private data for this context, if it is an nsISupports, |null| otherwise.
+ */
+ readonly attribute nsISupports privateData;
+
+ /**
+ * Retrieve the underlying context wrapped by this jsdIContext.
+ */
+ readonly attribute nsISupports wrappedContext;
+
+ /**
+ * Top of the scope chain for this context.
+ */
+ readonly attribute jsdIValue globalObject;
+
+ /**
+ * |true| if this context should be allowed to run scripts, |false|
+ * otherwise. This attribute is only valid for contexts which implement
+ * nsIScriptContext. Setting or getting this attribute on any other
+ * context will throw a NS_ERROR_NO_INTERFACE exception.
+ */
+ attribute boolean scriptsEnabled;
+};
+
+/**
+ * Stack frame objects. These are only valid inside the jsdIExecutionHook which
+ * gave it to you. After you return from that handler the bottom frame, and any
+ * frame you found attached through it, are invalidated via the jsdIEphemeral
+ * interface. Once a jsdIStackFrame has been invalidated all method and
+ * property accesses will throw a NS_ERROR_NOT_AVAILABLE exception.
+ */
+[scriptable, uuid(b6d50784-1dd1-11b2-a932-882246c6fe45)]
+interface jsdIStackFrame : jsdIEphemeral
+{
+ /** Internal use only. */
+ [noscript] readonly attribute JSDContext JSDContext;
+ /** Internal use only. */
+ [noscript] readonly attribute JSDThreadState JSDThreadState;
+ /** Internal use only. */
+ [noscript] readonly attribute JSDStackFrameInfo JSDStackFrameInfo;
+
+ /**
+ * True if stack frame represents a native frame.
+ */
+ readonly attribute boolean isNative;
+ /**
+ * True if stack frame represents a frame created as a result of a debugger
+ * evaluation.
+ */
+ readonly attribute boolean isDebugger;
+ /**
+ * True if stack frame is constructing a new object.
+ */
+ readonly attribute boolean isConstructing;
+
+ /**
+ * Link to the caller's stack frame.
+ */
+ readonly attribute jsdIStackFrame callingFrame;
+ /**
+ * Executon context.
+ */
+ readonly attribute jsdIContext executionContext;
+ /**
+ * Function name executing in this stack frame.
+ */
+ readonly attribute string functionName;
+ /**
+ * Script running in this stack frame, null for native frames.
+ */
+ readonly attribute jsdIScript script;
+ /**
+ * Current program counter in this stack frame.
+ */
+ readonly attribute unsigned long pc;
+ /**
+ * Current line number (using the script's pc to line map.)
+ */
+ readonly attribute unsigned long line;
+ /**
+ * Function object running in this stack frame.
+ */
+ readonly attribute jsdIValue callee;
+ /**
+ * Top object in the scope chain.
+ */
+ readonly attribute jsdIValue scope;
+ /**
+ * |this| object for this stack frame.
+ */
+ readonly attribute jsdIValue thisValue;
+ /**
+ * Evaluate arbitrary JavaScript in this stack frame.
+ * @param bytes Script to be evaluated.
+ * @param fileName Filename to compile this script under. This is the
+ * filename you'll see in error messages, etc.
+ * @param line Starting line number for this script. One based.
+ * @retval Result of evaluating the script.
+ */
+ boolean eval (in AString bytes, in string fileName,
+ in unsigned long line, out jsdIValue result);
+
+};
+
+/**
+ * Script object. In JavaScript engine terms, there's a single script for each
+ * function, and one for the top level script.
+ */
+[scriptable, uuid(a38f65ca-1dd1-11b2-95d5-ff2947e9c920)]
+interface jsdIScript : jsdIEphemeral
+{
+ /** Internal use only. */
+ [noscript] readonly attribute JSDContext JSDContext;
+ /** Internal use only. */
+ [noscript] readonly attribute JSDScript JSDScript;
+
+ /**
+ * Last version set on this context.
+ * Scripts typically select this with the "language" attribute.
+ * See the VERSION_* consts on jsdIDebuggerService.
+ */
+ readonly attribute long version;
+
+ /**
+ * Tag value guaranteed unique among jsdIScript objects. Useful as a
+ * hash key in script.
+ */
+ readonly attribute unsigned long tag;
+
+ /**
+ * FLAG_* values need to be kept in sync with JSD_SCRIPT_* #defines in
+ * jsdebug.h.
+ */
+
+ /**
+ * Determines whether or not to collect profile information for this
+ * script. The context flag FLAG_PROFILE_WHEN_SET decides the logic.
+ */
+ const unsigned long FLAG_PROFILE = 0x01;
+ /**
+ * Determines whether or not to ignore breakpoints, etc. in this script.
+ * The context flag JSD_DEBUG_WHEN_SET decides the logic.
+ */
+ const unsigned long FLAG_DEBUG = 0x02;
+
+ /**
+ * FLAG_* attributes from above, OR'd together.
+ */
+ attribute unsigned long flags;
+
+ /**
+ * Filename given for this script when it was compiled.
+ * This data is copied from the underlying structure when the jsdIScript
+ * instance is created and is therefore available even after the script is
+ * invalidated.
+ */
+ readonly attribute string fileName;
+ /**
+ * Function name for this script. "anonymous" for unnamed functions (or
+ * a function actually named anonymous), empty for top level scripts.
+ * This data is copied from the underlying structure when the jsdIScript
+ * instance is created and is therefore available even after the script is
+ * invalidated.
+ */
+ readonly attribute string functionName;
+ /**
+ * Fetch the function object as a jsdIValue.
+ */
+ readonly attribute jsdIValue functionObject;
+ /**
+ * Source code for this script, without function declaration.
+ */
+ readonly attribute AString functionSource;
+ /**
+ * Line number in source file containing the first line of this script.
+ * This data is copied from the underlying structure when the jsdIScript
+ * instance is created and is therefore available even after the script is
+ * invalidated.
+ */
+ readonly attribute unsigned long baseLineNumber;
+ /**
+ * Total number of lines in this script.
+ * This data is copied from the underlying structure when the jsdIScript
+ * instance is created and is therefore available even after the script is
+ * invalidated.
+ */
+ readonly attribute unsigned long lineExtent;
+
+ /**
+ * Number of times this script has been called.
+ */
+ readonly attribute unsigned long callCount;
+ /**
+ * Number of times this script called itself, directly or indirectly.
+ */
+ readonly attribute unsigned long maxRecurseDepth;
+ /**
+ * Shortest execution time recorded, in milliseconds.
+ */
+ readonly attribute double minExecutionTime;
+ /**
+ * Longest execution time recorded, in milliseconds.
+ */
+ readonly attribute double maxExecutionTime;
+ /**
+ * Total time spent in this function, in milliseconds.
+ */
+ readonly attribute double totalExecutionTime;
+ /**
+ * Shortest execution time recorded, in milliseconds, excluding time spent
+ * in other called code.
+ */
+ readonly attribute double minOwnExecutionTime;
+ /**
+ * Longest execution time recorded, in milliseconds, excluding time spent
+ * in other called code.
+ */
+ readonly attribute double maxOwnExecutionTime;
+ /**
+ * Total time spent in this function, in milliseconds, excluding time spent
+ * in other called code.
+ */
+ readonly attribute double totalOwnExecutionTime;
+
+ /**
+ * Clear profile data for this script.
+ */
+ void clearProfileData();
+ ...
[truncated message content] |