|
1 | 1 | import * as vscode from 'vscode';
|
2 | 2 | import * as child from 'child_process';
|
| 3 | +import * as path from 'path'; |
3 | 4 | import BaseLinter from './BaseLinter';
|
4 | 5 |
|
5 |
| -var isWindows = process.platform === 'win32'; |
| 6 | +let standardToArg: Map<string, string> = new Map<string, string>([ |
| 7 | + ['Verilog-95', '-g1995'], |
| 8 | + ['Verilog-2001', '-g2001'], |
| 9 | + ['Verilog-2005', '-g2005'], |
| 10 | + ['SystemVerilog2005', '-g2005-sv'], |
| 11 | + ['SystemVerilog2009', '-g2009'], |
| 12 | + ['SystemVerilog2012', '-g2012'], |
| 13 | +]); |
6 | 14 |
|
7 | 15 | export default class IcarusLinter extends BaseLinter {
|
8 |
| - private iverilogPath: string; |
9 |
| - private iverilogArgs: string; |
| 16 | + private configuration: vscode.WorkspaceConfiguration; |
| 17 | + private linterInstalledPath: string; |
| 18 | + private arguments: string; |
| 19 | + private includePath: string[]; |
| 20 | + private standards: Map<string, string>; |
10 | 21 | private runAtFileLocation: boolean;
|
11 | 22 |
|
12 | 23 | constructor(diagnosticCollection: vscode.DiagnosticCollection, logger: vscode.LogOutputChannel) {
|
13 | 24 | super('iverilog', diagnosticCollection, logger);
|
14 | 25 | vscode.workspace.onDidChangeConfiguration(() => {
|
15 |
| - this.getConfig(); |
| 26 | + this.updateConfig(); |
16 | 27 | });
|
17 |
| - this.getConfig(); |
| 28 | + this.updateConfig(); |
18 | 29 | }
|
19 | 30 |
|
20 |
| - private getConfig() { |
21 |
| - this.iverilogPath = <string>vscode.workspace.getConfiguration().get('verilog.linting.path'); |
22 |
| - this.iverilogArgs = <string>( |
23 |
| - vscode.workspace.getConfiguration().get('verilog.linting.iverilog.arguments') |
24 |
| - ); |
25 |
| - this.runAtFileLocation = <boolean>( |
26 |
| - vscode.workspace.getConfiguration().get('verilog.linting.iverilog.runAtFileLocation') |
| 31 | + private updateConfig() { |
| 32 | + this.linterInstalledPath = <string>( |
| 33 | + vscode.workspace.getConfiguration().get('verilog.linting.path') |
27 | 34 | );
|
| 35 | + this.configuration = vscode.workspace.getConfiguration('verilog.linting.iverilog'); |
| 36 | + this.arguments = <string>this.configuration.get('arguments'); |
| 37 | + let path = <string[]>this.configuration.get('includePath'); |
| 38 | + this.includePath = path.map((includePath: string) => this.resolvePath(includePath)); |
| 39 | + this.standards = new Map<string, string>([ |
| 40 | + ['verilog', this.configuration.get('verilogHDL.standard')], |
| 41 | + ['systemverilog', this.configuration.get('systemVerilog.standard')], |
| 42 | + ]); |
| 43 | + this.runAtFileLocation = <boolean>this.configuration.get('runAtFileLocation'); |
| 44 | + } |
| 45 | + |
| 46 | + // returns absolute path |
| 47 | + private resolvePath(inputPath: string): string { |
| 48 | + if (!path || path.isAbsolute(inputPath) || !vscode.workspace.workspaceFolders[0]) { |
| 49 | + return ''; |
| 50 | + } |
| 51 | + return path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, inputPath); |
28 | 52 | }
|
29 | 53 |
|
30 | 54 | protected lint(doc: vscode.TextDocument) {
|
31 |
| - this.logger.info('[iverilog-lint] iverilog lint requested'); |
32 |
| - let docUri: string = doc.uri.fsPath; //path of current doc |
33 |
| - let lastIndex: number = isWindows == true ? docUri.lastIndexOf('\\') : docUri.lastIndexOf('/'); |
34 |
| - let docFolder = docUri.substr(0, lastIndex); //folder of current doc |
35 |
| - let runLocation: string = |
36 |
| - this.runAtFileLocation == true ? docFolder : vscode.workspace.rootPath; //choose correct location to run |
37 |
| - let svArgs: string = doc.languageId == 'systemverilog' ? '-g2012' : ''; //SystemVerilog args |
38 |
| - let command: string = |
39 |
| - this.iverilogPath + |
40 |
| - 'iverilog ' + |
41 |
| - svArgs + |
42 |
| - ' -t null ' + |
43 |
| - this.iverilogArgs + |
44 |
| - ' "' + |
45 |
| - doc.fileName + |
46 |
| - '"'; //command to execute |
47 |
| - this.logger.info('[iverilog-lint] Execute command: ' + command); |
| 55 | + let binPath: string = path.join(this.linterInstalledPath, 'iverilog'); |
| 56 | + |
| 57 | + let args: string[] = []; |
| 58 | + args.push('-t null'); |
| 59 | + |
| 60 | + args.push(standardToArg.get(this.standards.get(doc.languageId))); |
| 61 | + args = args.concat(this.includePath.map((path: string) => '-I ' + path)); |
| 62 | + args.push(this.arguments); |
| 63 | + args.push(doc.uri.fsPath); |
48 | 64 |
|
49 |
| - var foo: child.ChildProcess = child.exec( |
| 65 | + let command: string = binPath + ' ' + args.join(' '); |
| 66 | + |
| 67 | + let cwd: string = this.runAtFileLocation |
| 68 | + ? path.dirname(doc.uri.fsPath) |
| 69 | + : vscode.workspace.workspaceFolders[0].uri.fsPath; |
| 70 | + |
| 71 | + this.logger.info('[iverilog-lint] Execute'); |
| 72 | + this.logger.info('[iverilog-lint] command: ' + command); |
| 73 | + this.logger.info('[iverilog-lint] cwd : ' + cwd); |
| 74 | + |
| 75 | + var _: child.ChildProcess = child.exec( |
50 | 76 | command,
|
51 |
| - { cwd: runLocation }, |
| 77 | + { cwd: cwd }, |
52 | 78 | (_error: Error, _stdout: string, stderr: string) => {
|
53 | 79 | let diagnostics: vscode.Diagnostic[] = [];
|
54 |
| - let lines = stderr.split(/\r?\n/g); |
55 | 80 | // Parse output lines
|
56 |
| - lines.forEach((line, _) => { |
57 |
| - if (line.startsWith(doc.fileName)) { |
58 |
| - line = line.replace(doc.fileName, ''); |
59 |
| - let terms = line.split(':'); |
60 |
| - let lineNum = parseInt(terms[1].trim()) - 1; |
61 |
| - if (terms.length == 3) { |
62 |
| - diagnostics.push({ |
63 |
| - severity: vscode.DiagnosticSeverity.Error, |
64 |
| - range: new vscode.Range(lineNum, 0, lineNum, Number.MAX_VALUE), |
65 |
| - message: terms[2].trim(), |
66 |
| - code: 'iverilog', |
67 |
| - source: 'iverilog', |
68 |
| - }); |
69 |
| - } else if (terms.length >= 4) { |
70 |
| - let sev: vscode.DiagnosticSeverity; |
71 |
| - if (terms[2].trim() == 'error') { |
| 81 | + // the message is something like this |
| 82 | + // /home/ubuntu/project1/module_1.sv:3: syntax error" |
| 83 | + // /home/ubuntu/project1/property_1.sv:3: error: Invalid module instantiation" |
| 84 | + stderr.split(/\r?\n/g).forEach((line, _) => { |
| 85 | + if (!line.startsWith(doc.fileName)) { |
| 86 | + return; |
| 87 | + } |
| 88 | + line = line.replace(doc.fileName, ''); |
| 89 | + let terms = line.split(':'); |
| 90 | + let lineNum = parseInt(terms[1].trim()) - 1; |
| 91 | + if (terms.length === 3) { |
| 92 | + diagnostics.push({ |
| 93 | + severity: vscode.DiagnosticSeverity.Error, |
| 94 | + range: new vscode.Range(lineNum, 0, lineNum, Number.MAX_VALUE), |
| 95 | + message: terms[2].trim(), |
| 96 | + code: 'iverilog', |
| 97 | + source: 'iverilog', |
| 98 | + }); |
| 99 | + } else if (terms.length >= 4) { |
| 100 | + let sev: vscode.DiagnosticSeverity; |
| 101 | + switch (terms[2].trim()) { |
| 102 | + case 'error': |
72 | 103 | sev = vscode.DiagnosticSeverity.Error;
|
73 |
| - } else if (terms[2].trim() == 'warning') { |
| 104 | + break; |
| 105 | + case 'warning': |
74 | 106 | sev = vscode.DiagnosticSeverity.Warning;
|
75 |
| - } else { |
| 107 | + break; |
| 108 | + default: |
76 | 109 | sev = vscode.DiagnosticSeverity.Information;
|
77 |
| - } |
78 |
| - diagnostics.push({ |
79 |
| - severity: sev, |
80 |
| - range: new vscode.Range(lineNum, 0, lineNum, Number.MAX_VALUE), |
81 |
| - message: terms[3].trim(), |
82 |
| - code: 'iverilog', |
83 |
| - source: 'iverilog', |
84 |
| - }); |
85 | 110 | }
|
| 111 | + diagnostics.push({ |
| 112 | + severity: sev, |
| 113 | + range: new vscode.Range(lineNum, 0, lineNum, Number.MAX_VALUE), |
| 114 | + message: terms[3].trim(), |
| 115 | + code: 'iverilog', |
| 116 | + source: 'Icarus Verilog', |
| 117 | + }); |
86 | 118 | }
|
87 | 119 | });
|
88 |
| - this.logger.info('[iverilog-lint] ' + diagnostics.length + ' errors/warnings returned'); |
| 120 | + if (diagnostics.length > 0) { |
| 121 | + this.logger.info('[iverilog-lint] ' + diagnostics.length + ' errors/warnings returned'); |
| 122 | + } |
89 | 123 | this.diagnosticCollection.set(doc.uri, diagnostics);
|
90 | 124 | }
|
91 | 125 | );
|
|
0 commit comments