From ceb442e931d5b35d35c60ede0e497a54096d4821 Mon Sep 17 00:00:00 2001 From: Sei Lisa Date: Sat, 2 Jan 2016 03:39:47 +0100 Subject: [PATCH] Improve error reporting, by printing the errored line and a caret (^), taking care to display the beginning of the token the error is at. --- lslopt/lslparse.py | 20 +++++++++----------- main.py | 14 +++++++++++--- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/lslopt/lslparse.py b/lslopt/lslparse.py index 0f0e3b4..b69eaae 100644 --- a/lslopt/lslparse.py +++ b/lslopt/lslparse.py @@ -60,14 +60,12 @@ def fieldpos(inp, sep, n): class EParse(Exception): def __init__(self, parser, msg): - errorpos = parser.errorpos - if parser.script[errorpos:errorpos+1] == '\n': - errorpos += 1 - lno = parser.script.count('\n', 0, errorpos) - cno = errorpos - fieldpos(parser.script, '\n', lno) + self.errorpos = parser.errorpos + self.lno = parser.script.count('\n', 0, self.errorpos) + self.cno = self.errorpos - fieldpos(parser.script, '\n', self.lno) # Note the column number reported is in bytes. - msg = u"(Line %d char %d): ERROR: %s" % (lno + 1, cno + 1, msg) + msg = u"(Line %d char %d): ERROR: %s" % (self.lno + 1, self.cno + 1, msg) super(EParse, self).__init__(msg) class EParseUEOF(EParse): @@ -309,11 +307,11 @@ class parser(object): def GetToken(self): """Lexer""" - # Keep track of the current position. If an error occurs, it will happen at the start of this token. - self.errorpos = self.pos - try: while self.pos < self.length: + # If an error occurs, it will happen at the start of this token. + self.errorpos = self.pos + c = self.script[self.pos] self.pos += 1 @@ -2388,14 +2386,14 @@ list lazy_list_set(list L, integer i, list v) # incomplete parsing pass, gathering globals with their types and # function arguments. And that's what we do. - self.pos = 0 + self.pos = self.errorpos = 0 self.tok = self.GetToken() self.globals = self.BuildTempGlobalsTable() # Restart - self.pos = 0 + self.pos = self.errorpos = 0 self.tok = self.GetToken() # Reserve spots at the beginning for functions we add diff --git a/main.py b/main.py index 6bf884a..076039f 100755 --- a/main.py +++ b/main.py @@ -19,16 +19,22 @@ # This is the main executable program that imports the libraries. -from lslopt.lslparse import parser,EParse +from lslopt.lslparse import parser,EParse,fieldpos from lslopt.lsloutput import outscript from lslopt.lsloptimizer import optimizer import sys, os, getopt, re import lslopt.lslcommon -VERSION = '0.1.3alpha' +VERSION = '0.2.0beta' +def ReportError(script, e): + sys.stderr.write(script[fieldpos(script, '\n', e.lno): + fieldpos(script, '\n', e.lno+1)-1] + '\n') + sys.stderr.write(' ' * e.cno + '^\n') + sys.stderr.write(e[0] + '\n') + class UniConvScript(object): '''Converts the script to Unicode, setting the properties required by EParse to report a meaningful error position. @@ -467,6 +473,8 @@ def main(): # need the result. UniConvScript(script).to_unicode() except EParse as e: + # We don't call ReportError to prevent problems due to + # displaying invalid UTF-8 sys.stderr.write(e[0] + '\n') return 1 script = PreparePreproc(script) @@ -502,7 +510,7 @@ def main(): try: ts = p.parse(script, options) except EParse as e: - sys.stderr.write(e[0] + '\n') + ReportError(script, e) return 1 del p, script