シンタックスエラーを示す
VSCodeで書いていると、文法エラーがあると赤い波線などが出て「問題」に一覧表示されます。
以下のような機能です。
この機能の実現は難儀しそうだと予想していましたが、ANTLRのエラーメッセージを少し加工してVSCodeに渡すとそれっぽい結果が出せたので楽でした。
ANTLR4のエラーメッセージ回収
ANTLR4はデフォルトだとエラーメッセージをコンソールに表示して終わってしまいますが、ErrorListnerというリスナを再設定してやるとその挙動を変更できます。
とても簡単で、以下のコードがカスタムErrorListnerです。
export class sv_error implements pg.ANTLRErrorListener<number> {
diags: any;
constructor() {
this.diags = [];
return this;
}
syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e) {
let diag = {};
diag["severity"] = vscls.DiagnosticSeverity.Error;
diag["range"] = {
start: {line: line - 1, character: charPositionInLine},
end: {line: line - 1, character: charPositionInLine}
}
diag["message"] = msg;
diag["source"] = "sv_parser";
this.diags.push(diag);
}
}
シンタックスエラーが起こると上記 syntaxErrorが呼ばれるので、そのたびにメッセージをLSP用の形式でdiagに保存していくだけです。
range情報があるとソースコード上に波線表示してくれるのでカッコいいわけですが、これもANTLR4から出てきます。
エラーメッセージをVSCodeに表示
以下のようにErrorListnerをカスタムに置き換えて(単に追加でも良い)やると、パース毎にエラー情報を回収できます。
// invoke main parsing
let chars = new pg.ANTLRInputStream(repl_src);
let lexer = new svlex.SystemVerilogLexer(chars);
let tokens = new pg.CommonTokenStream(lexer, svlex.SystemVerilogLexer.DEFAULT_TOKEN_CHANNEL);
let parser = new svpar.SystemVerilogParser(tokens);
let error = new sv_error.sv_error();
parser.removeErrorListeners();
parser.addErrorListener(error);
parser.buildParseTree = true;
これを元に、LSPで
connection.sendDiagnostics({
uri: uri,
diagnostics: sva.filedb[uri].err.diags
});
とすればVSCode上にエラー情報が表示されます。
送るべきデータ構造は公式の
https://microsoft.github.io/language-server-protocol/specification
interface Diagnostic {
で定義されています。