[javascriptlint-commit] SF.net SVN: javascriptlint:[231] trunk
Status: Beta
Brought to you by:
matthiasmiller
|
From: <mat...@us...> - 2008-08-28 04:34:13
|
Revision: 231
http://javascriptlint.svn.sourceforge.net/javascriptlint/?rev=231&view=rev
Author: matthiasmiller
Date: 2008-08-28 04:34:11 +0000 (Thu, 28 Aug 2008)
Log Message:
-----------
allow adjusting node positions when parsing scripts
Modified Paths:
--------------
trunk/pyjsl/jsparse.py
trunk/pyspidermonkey/pyspidermonkey.c
Modified: trunk/pyjsl/jsparse.py
===================================================================
--- trunk/pyjsl/jsparse.py 2008-08-28 00:25:42 UTC (rev 230)
+++ trunk/pyjsl/jsparse.py 2008-08-28 04:34:11 UTC (rev 231)
@@ -151,7 +151,7 @@
opcode = 'JSOP_CPP_COMMENT'
opcode = opcode[5:].lower()
- start_offset = match.start()+1
+ start_offset = match.start()
end_offset = match.end()
# Make sure it doesn't start in a string or regexp
@@ -177,15 +177,27 @@
else:
pos = match.start()+1
-def parse(script, error_callback):
+def parse(script, error_callback, startpos=None):
+ """ All node positions will be relative to startpos. This allows scripts
+ to be embedded in a file (for example, HTML).
+ """
def _wrapped_callback(line, col, msg):
assert msg.startswith('JSMSG_')
msg = msg[6:].lower()
error_callback(line, col, msg)
- return pyspidermonkey.parse(script, _Node, _wrapped_callback)
+ startpos = startpos or NodePos(0,0)
+ return pyspidermonkey.parse(script, _Node, _wrapped_callback,
+ startpos.line, startpos.col)
-def parsecomments(script, root_node):
+def parsecomments(script, root_node, startpos=None):
+ """ All node positions will be relative to startpos. This allows scripts
+ to be embedded in a file (for example, HTML).
+ """
+ # Use dummy text to rebase node positions.
+ if startpos:
+ script = ('\n' * startpos.line) + (' ' * startpos.col) + script
+
positions = NodePositions(script)
comment_ignore_ranges = NodeRanges()
@@ -195,7 +207,7 @@
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())
+ end_offset = positions.to_offset(node.end_pos()) - 1
comment_ignore_ranges.add(start_offset, end_offset)
for kid in node.kids:
if kid:
@@ -324,6 +336,45 @@
for text, result in tests:
self.assertEquals(is_compilable_unit(text), result)
+class TestLineOffset(unittest.TestCase):
+ def testErrorPos(self):
+ def geterror(script, startpos):
+ errors = []
+ def onerror(line, col, msg):
+ errors.append((line, col, msg))
+ parse(script, onerror, startpos)
+ self.assertEquals(len(errors), 1)
+ return errors[0]
+ self.assertEquals(geterror(' ?', None), (0, 1, 'syntax_error'))
+ self.assertEquals(geterror('\n ?', None), (1, 1, 'syntax_error'))
+ self.assertEquals(geterror(' ?', NodePos(1,1)), (1, 2, 'syntax_error'))
+ self.assertEquals(geterror('\n ?', NodePos(1,1)), (2, 1, 'syntax_error'))
+ def testNodePos(self):
+ def getnodepos(script, startpos):
+ root = parse(script, None, startpos)
+ self.assertEquals(root.kind, tok.LC)
+ var, = root.kids
+ self.assertEquals(var.kind, tok.VAR)
+ return var.start_pos()
+ self.assertEquals(getnodepos('var x;', None), NodePos(0,0))
+ self.assertEquals(getnodepos(' var x;', None), NodePos(0,1))
+ self.assertEquals(getnodepos('\n\n var x;', None), NodePos(2,1))
+ self.assertEquals(getnodepos('var x;', NodePos(3,4)), NodePos(3,4))
+ self.assertEquals(getnodepos(' var x;', NodePos(3,4)), NodePos(3,5))
+ self.assertEquals(getnodepos('\n\n var x;', NodePos(3,4)), NodePos(5,1))
+ def testComments(self):
+ def testcomment(comment, startpos, expectedpos):
+ root = parse(comment, None, startpos)
+ comment, = parsecomments(comment, root, startpos)
+ self.assertEquals(comment.start_pos(), expectedpos)
+ for comment in ('/*comment*/', '//comment'):
+ testcomment(comment, None, NodePos(0,0))
+ testcomment(' %s' % comment, None, NodePos(0,1))
+ testcomment('\n\n %s' % comment, None, NodePos(2,1))
+ testcomment('%s' % comment, NodePos(3,4), NodePos(3,4))
+ testcomment(' %s' % comment, NodePos(3,4), NodePos(3,5))
+ testcomment('\n\n %s' % comment, NodePos(3,4), NodePos(5,1))
+
if __name__ == '__main__':
unittest.main()
Modified: trunk/pyspidermonkey/pyspidermonkey.c
===================================================================
--- trunk/pyspidermonkey/pyspidermonkey.c 2008-08-28 00:25:42 UTC (rev 230)
+++ trunk/pyspidermonkey/pyspidermonkey.c 2008-08-28 04:34:11 UTC (rev 231)
@@ -124,17 +124,44 @@
typedef struct JSContextData {
PyObject* node_class;
PyObject* error_callback;
+ long int first_lineno;
+ long int first_index;
} JSContextData;
+static long int
+to_pyjsl_lineno(JSContextData* data, long int lineno) {
+ /* SpiderMonkey uses 1-based line numbers. */
+ return lineno + data->first_lineno - 1;
+}
+
+static long int
+to_pyjsl_index(JSContextData* data, long int lineno, long int index) {
+ /* SpiderMonkey uses 1-based line numbers. */
+ if (lineno - 1 == 0)
+ return index + data->first_index;
+ else
+ return index;
+}
+
+static JSTokenPtr
+to_pyjsl_pos(JSContextData* data, JSTokenPtr ptr) {
+ JSTokenPtr newptr = ptr;
+ newptr.index = to_pyjsl_index(data, ptr.lineno, ptr.index);
+ newptr.lineno = to_pyjsl_lineno(data, ptr.lineno);
+ return newptr;
+}
+
static void
error_reporter(JSContext* cx, const char* message, JSErrorReport* report)
{
JSContextData* data = JS_GetContextPrivate(cx);
- long int line = report->lineno - 1;
+ long int line = to_pyjsl_lineno(data, report->lineno);
long int col = -1;
- if (report->uclinebuf)
+ if (report->uclinebuf) {
col = report->uctokenptr - report->uclinebuf;
+ col = to_pyjsl_index(data, report->lineno, col);
+ }
// TODO: Check return value
(void)PyObject_CallFunction(data->error_callback, "lls",
@@ -169,6 +196,7 @@
JSContextData* data = JS_GetContextPrivate(context);
PyObject* pynode = NULL;
PyObject* kids = NULL;
+ JSTokenPtr tokenptr;
/* TODO: make sure no tuple item already exists */
@@ -192,13 +220,15 @@
goto fail;
/* pass the position */
- if (PyObject_SetAttrString(pynode, "_start_line", Py_BuildValue("i", jsnode->pn_pos.begin.lineno-1)) == -1)
+ tokenptr = to_pyjsl_pos(data, jsnode->pn_pos.begin);
+ if (PyObject_SetAttrString(pynode, "_start_line", Py_BuildValue("i", tokenptr.lineno)) == -1)
goto fail;
- if (PyObject_SetAttrString(pynode, "_start_col", Py_BuildValue("i", jsnode->pn_pos.begin.index)) == -1)
+ if (PyObject_SetAttrString(pynode, "_start_col", Py_BuildValue("i", tokenptr.index)) == -1)
goto fail;
- if (PyObject_SetAttrString(pynode, "_end_line", Py_BuildValue("i", jsnode->pn_pos.end.lineno-1)) == -1)
+ tokenptr = to_pyjsl_pos(data, jsnode->pn_pos.end);
+ if (PyObject_SetAttrString(pynode, "_end_line", Py_BuildValue("i", tokenptr.lineno)) == -1)
goto fail;
- if (PyObject_SetAttrString(pynode, "_end_col", Py_BuildValue("i", jsnode->pn_pos.end.index)) == -1)
+ if (PyObject_SetAttrString(pynode, "_end_col", Py_BuildValue("i", tokenptr.index)) == -1)
goto fail;
if ((jsnode->pn_type == TOK_NAME || jsnode->pn_type == TOK_DOT ||
@@ -370,8 +400,11 @@
error = "encountered an unknown error";
/* validate arguments */
- if (!PyArg_ParseTuple(args, "sOO", &m.script, &m.ctx_data.node_class, &m.ctx_data.error_callback))
+ if (!PyArg_ParseTuple(args, "sOOll", &m.script, &m.ctx_data.node_class,
+ &m.ctx_data.error_callback, &m.ctx_data.first_lineno,
+ &m.ctx_data.first_index)) {
return NULL;
+ }
if (!PyCallable_Check(m.ctx_data.node_class)) {
PyErr_SetString(PyExc_ValueError, "\"node_class\" must be callable");
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|