Reporting Errors
Good language tools are able to not only provide functionality, but report
errors if and when they occur, in a clear and informative manner. scarf
places priority on this; the user should be able to easily understand any
error, as well as where changes need to be made.
This is reflected in the Span class, which accompanies many
objects (including Tokens, Nodes, and any
errors) and provides an exact location in the source files, so that
errors may be reported.
To report these errors, the Report class can be used. This
class is created with a particular error location, but can have many labeled
sections of source code included in the error printout (see Report.label).
For example, take the following SystemVerilog code, referred to as test.v:
module test_module(;
endmodule
Notice how we forgot the ending parentheses before the semicolon. Attempting
to parse() this will result in a ParserResult.ParserErr;
the contained VerboseError provides a Span that could
be used to construct a Report
from scarf_python import parse, ParserResult, Report, ReportKind
with open("test.v", "r") as f:
content = f.read()
parse_result = parse(content, "test.v", ["."], [])
assert isinstance(parse_result, ParserResult.ParserErr)
err_span = parse_result.error.span
report = Report(ReportKind.Error(), err_span, "ERR", "Missing a )")
report.label(err_span, ReportKind.Error(), "Put a ) here")
report.print()
To display the content to a user, use the Report.print() or Report.eprint()
methods to print a Report to stdout or stderr,
respectively. Calling one of these on the above report produces
the following output
[ERR] Error: Missing a )
╭─[ test.v:1:20 ]
│
1 │ module test_module(;
│ ┬
│ ╰── Put a ) here
───╯
For convenience, both VerboseError and PreprocessorError
also contain a report method, which produces a Report suitable
for printing; one could instead modify the above code to use this directly
from scarf_python import parse, ParserResult, Report, ReportKind
with open("test.v", "r") as f:
content = f.read()
parse_result = parse(content, "test.v", ["."], [])
assert isinstance(parse_result, ParserResult.ParserErr)
report = parse_result.error.report()
report.print()
which produces the following verbose but informative message
[P1] Error: found ;, expected ), ., an identifier, {, a comma, (, input, output, inout, ref, supply0, supply1, tri, triand, trior, trireg, tri0, tri1, uwire, wire, wand, wor, $unit, signed, unsigned, [, interface, bit, logic, reg, byte, shortint, int, longint, integer, time, shortreal, real, realtime, struct, union, enum, string, chandle, virtual, event, type, interconnect, or var
╭─[ test.v:1:20 ]
│
1 │ module test_module(;
│ ┬
│ ╰── Didn't expect ;
───╯
Finally, if you ever find yourself using Span whose Span.file
doesn’t exist, use Report.include() to include file content associated with
a particular name, so that a Report can print appropriately