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):
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

14
main.py
View file

@ -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