001package gudusoft.gsqlparser.pp2;
002
003import gudusoft.gsqlparser.TSyntaxError;
004
005/**
006 * A single diagnostic event produced by the pp2 engine — a recovered parse
007 * failure, a tokenizer gap, a guard fall-through, etc.
008 *
009 * <p>Immutable. Carries the byte-span on the original input that the
010 * diagnostic refers to, a {@link Severity}, a human-readable message, and
011 * (optionally) the underlying {@link TSyntaxError} from the parser when the
012 * diagnostic was triggered by a parse failure.
013 *
014 * <p>Severity policy follows plan §12. Briefly: {@code INFO} for routine
015 * notes (e.g., region too large to parse), {@code WARNING} for recovered
016 * conditions (e.g., AST delegate guard fell through), {@code ERROR} for
017 * parse failures and renderer fall-throughs, {@code FATAL} for invariant
018 * violations that should never occur in practice.
019 */
020public final class FormatDiagnostic {
021
022    /** Severity level. See class Javadoc and plan §12 for the policy. */
023    public enum Severity {
024        INFO,
025        WARNING,
026        ERROR,
027        FATAL
028    }
029
030    private final Severity severity;
031    private final int startOffset;
032    private final int endOffset;
033    private final String message;
034    private final TSyntaxError parserError; // nullable
035
036    public FormatDiagnostic(Severity severity, int startOffset, int endOffset,
037                            String message) {
038        this(severity, startOffset, endOffset, message, null);
039    }
040
041    public FormatDiagnostic(Severity severity, int startOffset, int endOffset,
042                            String message, TSyntaxError parserError) {
043        if (severity == null) throw new NullPointerException("severity");
044        if (message == null) throw new NullPointerException("message");
045        if (startOffset < 0) {
046            throw new IllegalArgumentException("startOffset < 0: " + startOffset);
047        }
048        if (endOffset < startOffset) {
049            throw new IllegalArgumentException(
050                "endOffset < startOffset: " + endOffset + " < " + startOffset);
051        }
052        this.severity = severity;
053        this.startOffset = startOffset;
054        this.endOffset = endOffset;
055        this.message = message;
056        this.parserError = parserError;
057    }
058
059    public Severity getSeverity() { return severity; }
060    public int getStartOffset() { return startOffset; }
061    public int getEndOffset() { return endOffset; }
062    public String getMessage() { return message; }
063
064    /** May be {@code null} if the diagnostic did not originate from a parser failure. */
065    public TSyntaxError getParserError() { return parserError; }
066
067    @Override
068    public String toString() {
069        return "FormatDiagnostic{" + severity + " @" + startOffset + ".." + endOffset
070            + " " + message + (parserError != null ? " (parser)" : "") + "}";
071    }
072}