-
-
Notifications
You must be signed in to change notification settings - Fork 83
/
Copy pathVerilatorLinter.ts
149 lines (132 loc) · 5.11 KB
/
VerilatorLinter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// SPDX-License-Identifier: MIT
import * as vscode from 'vscode';
import * as child from 'child_process';
import * as path from 'path';
import * as process from 'process';
import BaseLinter from './BaseLinter';
import { Logger } from '../logger';
let isWindows = process.platform === 'win32';
export default class VerilatorLinter extends BaseLinter {
private configuration: vscode.WorkspaceConfiguration;
private linterInstalledPath: string;
private arguments: string;
private includePath: string[];
private runAtFileLocation: boolean;
private useWSL: boolean;
constructor(diagnosticCollection: vscode.DiagnosticCollection, logger: Logger) {
super('verilator', diagnosticCollection, logger);
vscode.workspace.onDidChangeConfiguration(() => {
this.updateConfig();
});
this.updateConfig();
}
private updateConfig() {
this.linterInstalledPath = <string>(
vscode.workspace.getConfiguration().get('verilog.linting.path')
);
this.configuration = vscode.workspace.getConfiguration('verilog.linting.verilator');
this.arguments = <string>this.configuration.get('arguments');
let path = <string[]>this.configuration.get('includePath');
this.includePath = path.map((includePath: string) => this.resolvePath(includePath));
this.runAtFileLocation = <boolean>this.configuration.get('runAtFileLocation');
this.useWSL = <boolean>this.configuration.get('useWSL');
}
protected splitTerms(line: string) {
let terms = line.split(':');
for (var i = 0; i < terms.length; i++) {
if (terms[i] === ' ') {
terms.splice(i, 1);
i--;
} else {
terms[i] = terms[i].trim();
}
}
return terms;
}
protected convertToSeverity(severityString: string): vscode.DiagnosticSeverity {
if (severityString.startsWith('Error')) {
return vscode.DiagnosticSeverity.Error;
} else if (severityString.startsWith('Warning')) {
return vscode.DiagnosticSeverity.Warning;
}
return vscode.DiagnosticSeverity.Information;
}
private convertToWslPath(inputPath: string): string {
let cmd: string = `wsl wslpath '${inputPath}'`;
return child.execSync(cmd, {}).toString().replace(/\r?\n/g, '');
}
protected lint(doc: vscode.TextDocument) {
let docUri: string = isWindows
? this.useWSL
? this.convertToWslPath(doc.uri.fsPath)
: doc.uri.fsPath.replace(/\\/g, '/')
: doc.uri.fsPath;
let docFolder: string = isWindows
? this.useWSL
? this.convertToWslPath(path.dirname(doc.uri.fsPath))
: path.dirname(doc.uri.fsPath).replace(/\\/g, '/')
: path.dirname(doc.uri.fsPath);
let cwd: string = this.runAtFileLocation
? isWindows
? path.dirname(doc.uri.fsPath.replace(/\\/g, '/'))
: docFolder
: vscode.workspace.workspaceFolders[0].uri.fsPath;
let verilator: string = isWindows
? this.useWSL
? 'wsl verilator'
: 'verilator_bin.exe'
: 'verilator';
let binPath = path.join(this.linterInstalledPath, verilator);
let args: string[] = [];
if (doc.languageId === 'systemverilog') {
args.push('-sv');
}
args.push('--lint-only');
args.push(`-I"${docFolder}"`);
args = args.concat(this.includePath.map((path: string) => `-I"${path}"`));
args.push(this.arguments);
args.push(`"${docUri}"`);
let command: string = binPath + ' ' + args.join(' ');
this.logger.info('[verilator] Execute');
this.logger.info('[verilator] command: ' + command);
this.logger.info('[verilator] cwd : ' + cwd);
var _: child.ChildProcess = child.exec(
command,
{ cwd: cwd },
(_error: Error, _stdout: string, stderr: string) => {
let diagnostics: vscode.Diagnostic[] = [];
stderr.split(/\r?\n/g).forEach((line, _) => {
if (line.search("No such file or directory") >= 0 || line.search("Not a directory") >= 0 || line.search("command not found") >= 0) {
this.logger.error(`Could not execute command: ${command}`);
return;
}
if (!line.startsWith('%') || line.indexOf(docUri) <= 0) {
return;
}
let rex = line.match(
/%(\w+)(-[A-Z0-9_]+)?:\s*(\w+:)?(?:[^:]+):\s*(\d+):(?:\s*(\d+):)?\s*(\s*.+)/
);
if (rex && rex[0].length > 0) {
let lineNum = Number(rex[4]) - 1;
let colNum = Number(rex[5]) - 1;
// Type of warning is in rex[2]
colNum = isNaN(colNum) ? 0 : colNum; // for older Verilator versions (< 4.030 ~ish)
if (!isNaN(lineNum)) {
diagnostics.push({
severity: this.convertToSeverity(rex[1]),
range: new vscode.Range(lineNum, colNum, lineNum, Number.MAX_VALUE),
message: rex[6],
code: 'verilator',
source: 'verilator',
});
}
return;
}
this.logger.warn('[verilator] failed to parse error: ' + line);
});
this.logger.info(`[verilator] ${diagnostics.length} errors/warnings returned`);
this.diagnosticCollection.set(doc.uri, diagnostics);
}
);
}
}