UNPKG

@imc-trading/svlangserver

Version:
232 lines (231 loc) 9.34 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.VerilogDiagnostics = void 0; const node_1 = require("vscode-languageserver/node"); const genutils_1 = require("./genutils"); const path = require('path'); function getVerilatorSeverity(severityString) { let result = node_1.DiagnosticSeverity.Information; if (severityString.startsWith('Error')) { result = node_1.DiagnosticSeverity.Error; } else if (severityString.startsWith('Warning')) { result = node_1.DiagnosticSeverity.Warning; } return result; } function parseVerilatorDiagnostics(stdout, stderr, file, whitelistedMessages = []) { let diagnostics = []; let lines = stderr.split(/\r?\n/g); // RegExp expression for matching Verilator messages // Group 1: Severity // Group 2: Type (optional) // Group 3: Filename // Group 4: Line number // Group 5: Column number (optional) // Group 6: Message let regex = new RegExp(String.raw `%(Error|Warning)(-[A-Z0-9_]+)?: (${file.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}):(\d+):(?:(\d+):)? (.*)`, 'i'); // Parse output lines for (let i = 0; i < lines.length; ++i) { const line = lines[i]; let terms = line.match(regex); if (terms != null) { let severity = getVerilatorSeverity(terms[1]); let message = ""; let lineNum = parseInt(terms[4]) - 1; let colNum = 0; let colNumEnd = 0; if (terms[5]) { colNum = parseInt(terms[5]) - 1; } message = terms[6]; let messageWhiteListed = false; for (let whitelistedMessage of whitelistedMessages) { if (message.search(whitelistedMessage) >= 0) { messageWhiteListed = true; break; } } if (messageWhiteListed) { continue; } // Match the ^~~~~~~ under the error message if (/\s*\^~+/.exec(lines[i + 2])) { let startColNum = lines[i + 2].indexOf('|') + 2; colNum = lines[i + 2].indexOf('^'); colNum = colNum > startColNum ? colNum - startColNum : colNum; colNumEnd = lines[i + 2].lastIndexOf('~'); colNumEnd = colNumEnd > startColNum ? colNumEnd - startColNum : colNumEnd; i += 2; } if ((lineNum != NaN) && (colNum != NaN)) { diagnostics.push({ severity: severity, range: node_1.Range.create(lineNum, colNum, lineNum, colNumEnd < colNum ? colNum : colNumEnd), message: message, code: 'verilator', source: 'verilator' }); } } } return diagnostics; } function getIcarusSeverity(severityString, message) { let result = node_1.DiagnosticSeverity.Information; if (severityString === 'error' || message === 'syntax error') { result = node_1.DiagnosticSeverity.Error; } else if (severityString === 'warning') { result = node_1.DiagnosticSeverity.Warning; } return result; } function parseIcarusDiagnostics(stdout, stderr, file, whitelistedMessages = []) { let diagnostics = []; let lines = stderr.split(/\r?\n/g); // RegExp expression for matching Icarus messages // Group 1: Filename // Group 2: Line number // Group 3: Severity (optional) // Group 4: Message let regex = new RegExp(String.raw `(${file.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}):(\d+):(?: (error|warning):)? (.*)`, 'i'); // Parse output lines for (let i = 0; i < lines.length; ++i) { const line = lines[i]; let terms = line.match(regex); if (terms != null) { let message = terms[4]; let severity = getIcarusSeverity(terms[3], message); let lineNum = parseInt(terms[2]) - 1; let messageWhiteListed = false; for (let whitelistedMessage of whitelistedMessages) { if (message.search(whitelistedMessage) >= 0) { messageWhiteListed = true; break; } } if (messageWhiteListed) { continue; } if (lineNum != NaN) { diagnostics.push({ severity: severity, range: node_1.Range.create(lineNum, 0, lineNum, 0), message: message, code: 'iverilog', source: 'iverilog' }); } } } return diagnostics; } class VerilogDiagnostics { constructor(indexer) { this._linter = 'icarus'; this._command = ""; this._defines = []; this._optionsFile = ""; this._childProcMngr = new genutils_1.ChildProcManager(); this._delayedCaller = new genutils_1.DelayedCaller(); this._whitelistedMessages = []; this._indexer = indexer; } setCommand(cmd) { this._command = cmd; } setLinter(linter) { this._linter = linter; } setOptionsFile(file) { this._optionsFile = file; } setWhitelistedMessages(msgs) { this._whitelistedMessages = msgs.map(m => new RegExp(m)); } setDefines(defines) { this._defines = defines || []; } _lintImmediate(file, text) { this._childProcMngr.kill(file); return new Promise((resolve, reject) => { let fileWithoutRoot = file.slice(path.parse(file).root.length); let actFile = text == undefined ? file : genutils_1.tmpFileManager.getTmpFilePath("sources", fileWithoutRoot); let optionsFile = this._optionsFile; let vcTmpFileNum; if (text != undefined) { genutils_1.fsWriteFileSync(actFile, text); // if file write takes too long and another process started in the interim this._childProcMngr.kill(file); if (this._indexer.fileHasPkg(file)) { let vcFileContent = this._indexer.getOptionsFileContent() .map(line => { return (line.endsWith(file)) ? line.slice(0, line.length - file.length) + actFile : line; }) .join('\n'); vcTmpFileNum = genutils_1.tmpFileManager.getFreeTmpFileNum("vcfiles"); let tmpVcFile = genutils_1.tmpFileManager.getTmpFilePath("vcfiles", `lint${vcTmpFileNum}.vc`); genutils_1.fsWriteFileSync(tmpVcFile, vcFileContent); optionsFile = tmpVcFile; // if file write takes too long and another process started in the interim this._childProcMngr.kill(file); } } let definesArg = this._defines.length > 0 ? this._defines.map(d => ` +define+${d}`).join('') : ""; let optionsFileArg = optionsFile ? ' -f ' + optionsFile : ""; let actFileArg = this._indexer.isMustSrcFile(file) ? "" : " " + actFile; let command = this._command + definesArg + optionsFileArg + actFileArg; //ConnectionLogger.log(`DEBUG: verilator command ${command}`); this._childProcMngr.run(file, command, (status, error, stdout, stderr) => { if (optionsFile != this._optionsFile) { genutils_1.tmpFileManager.returnFreeTmpFileNum("vcfiles", vcTmpFileNum); } if (status) { switch (this._linter) { case "icarus": resolve(parseIcarusDiagnostics(stdout, stderr, actFile, this._whitelistedMessages)); break; case "verilator": resolve(parseVerilatorDiagnostics(stdout, stderr, actFile, this._whitelistedMessages)); break; default: reject(new Error(`Unknown linter ${this._linter}`)); break; } } else { resolve([]); } }); }); } lint(file, text) { try { if (text == undefined) { return this._lintImmediate(file, text) .catch(error => { genutils_1.ConnectionLogger.error(error); return []; }); } else { return this._delayedCaller.run(file, (success) => { if (!!success) { return this._lintImmediate(file, text); } return []; }, (error) => { genutils_1.ConnectionLogger.error(error); return []; }); } } catch (error) { genutils_1.ConnectionLogger.error(error); return Promise.resolve([]); } } cleanupTmpFiles() { genutils_1.tmpFileManager.cleanupTmpFiles(); } } exports.VerilogDiagnostics = VerilogDiagnostics;