Improve error reporting, by printing the errored line and a caret (^), taking care to display the beginning of the token the error is at.

This commit is contained in:
Sei Lisa 2016-01-02 03:39:47 +01:00
parent f97cef2a38
commit ceb442e931
2 changed files with 20 additions and 14 deletions

View file

@ -60,14 +60,12 @@ def fieldpos(inp, sep, n):
class EParse(Exception): class EParse(Exception):
def __init__(self, parser, msg): def __init__(self, parser, msg):
errorpos = parser.errorpos self.errorpos = parser.errorpos
if parser.script[errorpos:errorpos+1] == '\n': self.lno = parser.script.count('\n', 0, self.errorpos)
errorpos += 1 self.cno = self.errorpos - fieldpos(parser.script, '\n', self.lno)
lno = parser.script.count('\n', 0, errorpos)
cno = errorpos - fieldpos(parser.script, '\n', lno)
# Note the column number reported is in bytes. # 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) super(EParse, self).__init__(msg)
class EParseUEOF(EParse): class EParseUEOF(EParse):
@ -309,11 +307,11 @@ class parser(object):
def GetToken(self): def GetToken(self):
"""Lexer""" """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: try:
while self.pos < self.length: 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] c = self.script[self.pos]
self.pos += 1 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 # incomplete parsing pass, gathering globals with their types and
# function arguments. And that's what we do. # function arguments. And that's what we do.
self.pos = 0 self.pos = self.errorpos = 0
self.tok = self.GetToken() self.tok = self.GetToken()
self.globals = self.BuildTempGlobalsTable() self.globals = self.BuildTempGlobalsTable()
# Restart # Restart
self.pos = 0 self.pos = self.errorpos = 0
self.tok = self.GetToken() self.tok = self.GetToken()
# Reserve spots at the beginning for functions we add # Reserve spots at the beginning for functions we add

14
main.py
View file

@ -19,16 +19,22 @@
# This is the main executable program that imports the libraries. # 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.lsloutput import outscript
from lslopt.lsloptimizer import optimizer from lslopt.lsloptimizer import optimizer
import sys, os, getopt, re import sys, os, getopt, re
import lslopt.lslcommon 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): class UniConvScript(object):
'''Converts the script to Unicode, setting the properties required by '''Converts the script to Unicode, setting the properties required by
EParse to report a meaningful error position. EParse to report a meaningful error position.
@ -467,6 +473,8 @@ def main():
# need the result. # need the result.
UniConvScript(script).to_unicode() UniConvScript(script).to_unicode()
except EParse as e: except EParse as e:
# We don't call ReportError to prevent problems due to
# displaying invalid UTF-8
sys.stderr.write(e[0] + '\n') sys.stderr.write(e[0] + '\n')
return 1 return 1
script = PreparePreproc(script) script = PreparePreproc(script)
@ -502,7 +510,7 @@ def main():
try: try:
ts = p.parse(script, options) ts = p.parse(script, options)
except EParse as e: except EParse as e:
sys.stderr.write(e[0] + '\n') ReportError(script, e)
return 1 return 1
del p, script del p, script