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