Skip to content

Improve ParseException for better parsing #532

@moosefriend

Description

@moosefriend

Problem Description

When calling the CLI of the compiler for a KSP script which has an error, then the message of the ParseException also contains the line number and the line content. So it's hard to extract the actual error message.

How to reproduce

I'm calling the compiler from CLI using the following command:

C:\Python312\python.exe compiler\ksp_compiler.py --extra_syntax_check --indent-size 4 test-in.ksp test-out.ksp

"test-in.ksp" contains the following code:

on init
    declare $b
    $a := $b + 1
end on

This will throw a ksp_compile.ParseException of the problem:

Traceback (most recent call last):
  ...
  File "C:\zz_Kontakt_Script_IDE\vscode-ksp-compiler\vscode_extension\sublime_ksp\compiler\ksp_compiler.py", line 1362, in modifyID
    raise ksp_ast.ParseException(node, "%s has not been declared!" % name)
  File "<string>", line 7
ksp_ast.ParseException: $a has not been declared!

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  ...
  File "C:\zz_Kontakt_Script_IDE\vscode-ksp-compiler\vscode_extension\sublime_ksp\compiler\ksp_compiler.py", line 2574, in compile
    raise ParseException(line, message)
ksp_compiler.ParseException: $a has not been declared! (line 7)

$a := $b + 1

<main script>: 3

Now even when writing a wrapper to extract the relevant information from the ParseException, the message also contains the actual line and the file and line number:

from ksp_compiler import main, ParseException

try:
    # Call the main function from ksp_compiler
    main()
except ParseException as ex:
        error_message = ex.message
        error_command = ex.line.command
        error_filename = ex.line.filename
        error_lineno = ex.line.lineno
        print(f">>> Message:\n{error_message}")
        print(f">>> Command:\n{error_command}")
        print(f">>> File:\n{error_filename}")
        print(f">>> Line:\n{error_lineno}")

Output:

>>> Message:
$a has not been declared! (line 7)

$a := $b + 1

<main script>: 3
>>> Command:
    $a := $b + 1
>>> File:
None
>>> Line:
3

Analysis

The code which constructs the message is in line 223:

class ParseException(ExceptionWithMessage):
'''Parse Exceptions for parse errors raised before AST lex/yacc parsing'''
def __init__(self, line, message, no_traceback = False):
if no_traceback:
utils.disable_traceback()
if line.calling_lines:
macro_chain = '\n'.join(['=> {}'.format(l.command.strip()) for l in line.calling_lines])
line_content = 'Macro traceback:\n{}\n{}'.format(macro_chain, str(line).strip())
else:
line_content = str(line).strip()
msg = "%s\n\n%s\n\n%s" % (message, line_content, line.get_locations_string())
Exception.__init__(self, msg)
self.line = line
self.message = msg

Proposal

It would be great if the ParseException.message only contains the error message without further information.
If a string is requested of the ParseException (__str__ method) then the current output could be constructed.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions