diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b8fb88..03ab503 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,15 +7,20 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
## [0.3.2] - 2023-11-01
Bug 修复
-- 修复文档化input, output处注释无法正常显示到文档的 bug
+- 修复文档化 input, output 处注释无法正常显示到文档的 bug
- 修复 iverilog 仿真功能中,将重复的路径作为编译参数编译的 bug
-- 修复 iverilog 仿真功能中,将 `include 加入或去除后,无法通过仿真编译的 bug (没有更新 instance 的 instModPathStatus 属性)
+- 修复 iverilog 仿真功能中,将 `include
加入或去除后,无法通过仿真编译的 bug (没有更新 instance 的 instModPathStatus 属性)
+- 修复其他已知 bug
-Feat
+Change
+- 将插件的工作状态显示在 vscode 下侧的状态栏上,利于用户了解目前的设置状态
+- 优化项目配置目录
+
+Feature
- 增加对 XDC,TCL 等脚本的 LSP 支持
-- 增加 verilog, vhdl, xdc, tcl 等语言的图标
-- 增加对于 vivado 的支持,用户可以通过添加 vivado 路径的方式(或者将 bin 文件夹添加到环境变量,默认路径为 C:\Xilinx\Vivado\2018.3\bin)来使用 vivado 的仿真和自动纠错
-- 增加对于 modelsim 的支持,用户可以通过添加 modelsim 安装路径(或者将 bin 文件夹添加到环境变量,默认路径为 C:\modeltech64_10.4\win64)来使用 vivado 的仿真和自动纠错
+- 增加 verilog, vhdl, xdc, tcl, vvp 等语言的工作区图标
+- 增加对于 vivado, modelsim, verilator 的支持,用户可以通过设置 `function.lsp.linter.vhdl.diagnostor`(设置 vhdl) 和 `function.lsp.linter.vlog.diagnostor`(设置 verilog) 来使用这些第三方工具的仿真和自动纠错。
+- 增加对于 TCL, XDC, VVP 等脚本的 LSP 和 语法高亮 支持
## [0.1.23] - 2022-12-24
- Finish the css of documentation, see `./css/documentation.css` for detail.
diff --git a/config/vvp.configuration.json b/config/vvp.configuration.json
new file mode 100644
index 0000000..ad4745f
--- /dev/null
+++ b/config/vvp.configuration.json
@@ -0,0 +1,17 @@
+{
+ "comments": {
+ "lineComment": "#"
+ },
+ "brackets": [
+ ["{", "}"],
+ ["[", "]"],
+ ["(", ")"]
+ ],
+ "autoClosingPairs": [
+ { "open": "(", "close": ")" },
+ { "open": "[", "close": "]" },
+ { "open": "'", "close": "'", "notIn": ["string"] },
+ { "open": "\"", "close": "\"", "notIn": ["string"] },
+ { "open": "/*", "close": " */", "notIn": ["string"] }
+ ]
+}
\ No newline at end of file
diff --git a/images/svg/dark/vlang.svg b/images/svg/dark/vlang.svg
new file mode 100644
index 0000000..450afcb
--- /dev/null
+++ b/images/svg/dark/vlang.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/images/svg/dark/vvp.svg b/images/svg/dark/vvp.svg
new file mode 100644
index 0000000..6059c47
--- /dev/null
+++ b/images/svg/dark/vvp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/images/svg/light/vvp.svg b/images/svg/light/vvp.svg
new file mode 100644
index 0000000..6059c47
--- /dev/null
+++ b/images/svg/light/vvp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/package.json b/package.json
index 7a1b401..539dfa7 100644
--- a/package.json
+++ b/package.json
@@ -33,11 +33,6 @@
"Snippets"
],
"activationEvents": [
- "onLanguage:verilog",
- "onLanguage:vhdl",
- "onLanguage:systemverilog",
- "onCommand:digital-ide.property-json.generate",
- "onCommand:digital-ide.property-json.overwrite",
"workspaceContains:.vscode/property.json"
],
"contributes": {
@@ -831,6 +826,21 @@
],
"configuration": "./config/link.configuration.json"
},
+ {
+ "id": "vvp",
+ "aliases": [
+ "VivadoVerificationPlan"
+ ],
+ "extensions": [
+ ".vvp",
+ ".VVP"
+ ],
+ "configuration": "./config/vvp.configuration.json",
+ "icon": {
+ "dark": "./images/svg/dark/vvp.svg",
+ "light": "./images/svg/light/vvp.svg"
+ }
+ },
{
"id": "digital-ide-output",
"mimetypes": [
@@ -863,7 +873,7 @@
{
"language": "vhdl",
"scopeName": "source.vhdl",
- "path": "./syntaxes/vhdl.json"
+ "path": "./syntaxes/vhdl.tmLanguage.json"
},
{
"language": "verilog",
@@ -875,6 +885,11 @@
"scopeName": "source.systemverilog",
"path": "./syntaxes/systemverilog.json"
},
+ {
+ "language": "vvp",
+ "scopeName": "source.vvp",
+ "path": "./syntaxes/vvp.tmLanguage.json"
+ },
{
"language": "digital-ide-output",
"scopeName": "digital-ide.output",
diff --git a/src/function/index.ts b/src/function/index.ts
index c1ca646..0c0f8c7 100644
--- a/src/function/index.ts
+++ b/src/function/index.ts
@@ -78,16 +78,23 @@ function registerLsp(context: vscode.ExtensionContext) {
vscode.languages.registerCompletionItemProvider(vlogSelector, lspCompletion.vlogMacroCompletionProvider, '`');
vscode.languages.registerCompletionItemProvider(vlogSelector, lspCompletion.vlogPositionPortProvider, '.');
vscode.languages.registerCompletionItemProvider(vlogSelector, lspCompletion.vlogCompletionProvider);
- vscode.languages.registerDocumentSemanticTokensProvider(vlogSelector, lspDocSemantic.vlogDocSenmanticProvider, lspDocSemantic.vlogLegend);
+ // vscode.languages.registerDocumentSemanticTokensProvider(vlogSelector, lspDocSemantic.vlogDocSenmanticProvider, lspDocSemantic.vlogLegend);
+
+
+
+ // vhdl lsp
+
+ vscode.languages.registerCompletionItemProvider(vhdlSelector, lspCompletion.vhdlCompletionProvider);
+
// tcl lsp
vscode.languages.registerCompletionItemProvider(tclSelector, lspCompletion.tclCompletionProvider);
- lspLinter.vlogLinter.initialise();
+ // lsp linter
+ // make first symbols in workspace
lspCore.hdlSymbolStorage.initialise();
-
- // vhdl lsp
-
+ lspLinter.vlogLinterManager.initialise();
+ lspLinter.vhdlLinterManager.initialise();
}
diff --git a/src/function/lsp/completion/index.ts b/src/function/lsp/completion/index.ts
index f6ccdb7..36bf3e4 100644
--- a/src/function/lsp/completion/index.ts
+++ b/src/function/lsp/completion/index.ts
@@ -1,4 +1,5 @@
import { vlogCompletionProvider, vlogIncludeCompletionProvider, vlogMacroCompletionProvider, vlogPositionPortProvider } from './vlog';
+import { vhdlCompletionProvider } from './vhdl';
import { tclCompletionProvider } from './tcl';
export {
@@ -6,5 +7,6 @@ export {
vlogIncludeCompletionProvider,
vlogMacroCompletionProvider,
vlogPositionPortProvider,
+ vhdlCompletionProvider,
tclCompletionProvider
};
\ No newline at end of file
diff --git a/src/function/lsp/completion/vhdl.ts b/src/function/lsp/completion/vhdl.ts
new file mode 100644
index 0000000..cf01522
--- /dev/null
+++ b/src/function/lsp/completion/vhdl.ts
@@ -0,0 +1,212 @@
+import * as vscode from 'vscode';
+import * as fs from 'fs';
+
+import * as util from '../util';
+import { hdlParam } from '../../../hdlParser';
+import { AbsPath, MainOutput, RelPath, ReportType } from '../../../global';
+import { Define, Include, RawSymbol } from '../../../hdlParser/common';
+import { HdlInstance, HdlModule } from '../../../hdlParser/core';
+import { vhdlKeyword } from '../util/keyword';
+import { hdlPath } from '../../../hdlFs';
+import { hdlSymbolStorage } from '../core';
+
+class VhdlCompletionProvider implements vscode.CompletionItemProvider {
+ public async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): Promise | null | undefined> {
+ // console.log('VhdlCompletionProvider');
+
+ try {
+ const filePath = hdlPath.toSlash(document.fileName);
+
+ // 1. provide keyword
+ const completions = this.makeKeywordItems(document, position);
+ completions.push(...this.makeCompilerKeywordItems(document, position));
+ completions.push(...this.makeSystemKeywordItems(document, position));
+
+ const symbolResult = await hdlSymbolStorage.getSymbol(filePath);
+ if (!symbolResult) {
+ return completions;
+ }
+
+ console.log('vhdl symbol result');
+
+
+ // locate at one module
+ const scopeSymbols = util.filterSymbolScope(position, symbolResult.content);
+ if (!scopeSymbols ||
+ !scopeSymbols.module ||
+ !hdlParam.hasHdlModule(filePath, scopeSymbols.module.name)) {
+ // MainOutput.report('Fail to get HdlModule ' + filePath + ' ' + scopeSymbols?.module.name, ReportType.Debug);
+ return completions;
+ }
+
+ // find wrapper module
+ const currentModule = hdlParam.getHdlModule(filePath, scopeSymbols.module.name);
+ if (!currentModule) {
+ return completions;
+ }
+
+ // 3. provide modules
+ const suggestModulesPromise = this.provideModules(document, position, filePath, symbolResult.macro.includes);
+
+ // 4. provide params and ports of wrapper module
+ const suggestParamsPortsPromise = this.provideParamsPorts(currentModule);
+
+ // 5. provide nets
+ const suggestNetsPromise = this.provideNets(scopeSymbols.symbols);
+
+ // collect
+ completions.push(...await suggestModulesPromise);
+ completions.push(...await suggestParamsPortsPromise);
+ completions.push(...await suggestNetsPromise);
+
+ return completions;
+
+ } catch (err) {
+ console.log(err);
+ }
+ }
+
+ private makeKeywordItems(document: vscode.TextDocument, position: vscode.Position): vscode.CompletionItem[] {
+ const vhdlKeywordItem = [];
+ for (const keyword of vhdlKeyword.keys()) {
+ const clItem = this.makekeywordCompletionItem(keyword);
+ vhdlKeywordItem.push(clItem);
+ }
+
+ return vhdlKeywordItem;
+ }
+
+ private makeCompilerKeywordItems(document: vscode.TextDocument, position: vscode.Position): vscode.CompletionItem[] {
+ const items = [];
+ const targetRange = document.getWordRangeAtPosition(position, /[`_0-9a-zA-Z]+/);
+ const targetWord = document.getText(targetRange);
+ const prefix = targetWord.startsWith('`') ? '' : '`';
+ for (const keyword of vhdlKeyword.compilerKeys()) {
+ const clItem = new vscode.CompletionItem(keyword, vscode.CompletionItemKind.Keyword);
+ clItem.insertText = new vscode.SnippetString(prefix + keyword);
+ clItem.detail = 'compiler directive';
+ items.push(clItem);
+ }
+ return items;
+ }
+
+ private makeSystemKeywordItems(document: vscode.TextDocument, position: vscode.Position): vscode.CompletionItem[] {
+ const items = [];
+ for (const keyword of vhdlKeyword.systemKeys()) {
+ const clItem = new vscode.CompletionItem(keyword, vscode.CompletionItemKind.Method);
+ clItem.insertText = new vscode.SnippetString('\\$' + keyword + '($1);');
+ clItem.detail = 'system task';
+ items.push(clItem);
+ }
+ return items;
+ }
+
+
+ private makekeywordCompletionItem(keyword: string): vscode.CompletionItem {
+ const clItem = new vscode.CompletionItem(keyword, vscode.CompletionItemKind.Keyword);
+ clItem.detail = 'keyword';
+
+ switch (keyword) {
+ case 'begin': clItem.insertText = new vscode.SnippetString("begin$1\nend"); break;
+ case 'function': clItem.insertText = new vscode.SnippetString("function ${1:name}\n\nendfunction"); break;
+ default: break;
+ }
+ return clItem;
+ }
+
+ private async provideModules(document: vscode.TextDocument, position: vscode.Position, filePath: AbsPath, includes: Include[]): Promise {
+ const suggestModules: vscode.CompletionItem[] = [];
+
+ const lspVhdlConfig = vscode.workspace.getConfiguration('function.lsp.completion.vhdl');
+ const autoAddInclude: boolean = lspVhdlConfig.get('autoAddInclude', true);
+ const completeWholeInstante: boolean = lspVhdlConfig.get('completeWholeInstante', true);
+
+ const includePaths = new Set();
+ let lastIncludeLine = 0;
+ for (const include of includes) {
+ const absIncludePath = hdlPath.rel2abs(filePath, include.path);
+ includePaths.add(absIncludePath);
+ lastIncludeLine = Math.max(include.range.end.line, lastIncludeLine);
+ }
+ const insertPosition = new vscode.Position(lastIncludeLine, 0);
+ const insertRange = new vscode.Range(insertPosition, insertPosition);
+ const fileFolder = hdlPath.resolve(filePath, '..');
+
+ // used only when completeWholeInstante is true
+ let completePrefix = '';
+ if (completeWholeInstante) {
+ const wordRange = document.getWordRangeAtPosition(position);
+ const countStart = wordRange ? wordRange.start.character : position.character;
+ const spaceNumber = Math.floor(countStart / 4) * 4;
+ console.log(wordRange, countStart, spaceNumber);
+
+ completePrefix = ' '.repeat(spaceNumber);
+ }
+
+
+ // for (const module of hdlParam.getAllHdlModules()) {
+ // const clItem = new vscode.CompletionItem(module.name, vscode.CompletionItemKind.Class);
+
+ // // feature 1 : auto add include path if there's no corresponding include path
+ // if (autoAddInclude && !includePaths.has(module.path)) {
+ // const relPath: RelPath = hdlPath.relative(fileFolder, module.path);
+ // const includeString = '`include "' + relPath + '"\n';
+ // const textEdit = new vscode.TextEdit(insertRange, includeString);
+ // clItem.additionalTextEdits = [textEdit];
+ // }
+
+ // // feature 2 : auto complete instance
+ // if (completeWholeInstante) {
+ // const snippetString = instanceVhdlCode(module, '', true);
+ // clItem.insertText = new vscode.SnippetString(snippetString);
+ // }
+
+ // clItem.detail = 'module';
+ // suggestModules.push(clItem);
+ // }
+
+ return suggestModules;
+ }
+
+ private async provideParamsPorts(module: HdlModule): Promise {
+ if (!module) {
+ return [];
+ }
+ const suggestParamsPorts = [];
+ for (const param of module.params) {
+ const clItem = new vscode.CompletionItem(param.name, vscode.CompletionItemKind.Constant);
+ clItem.detail = 'param';
+ suggestParamsPorts.push(clItem);
+ }
+
+ for (const port of module.ports) {
+ const clItem = new vscode.CompletionItem(port.name, vscode.CompletionItemKind.Interface);
+ clItem.detail = 'port';
+ suggestParamsPorts.push(clItem);
+ }
+
+ return suggestParamsPorts;
+ }
+
+ private async provideNets(symbols: RawSymbol[]): Promise {
+ if (!symbols) {
+ return [];
+ }
+ const suggestNets = [];
+ for (const symbol of symbols) {
+ if (symbol.type === 'wire' || symbol.type === 'reg') {
+ const clItem = new vscode.CompletionItem(symbol.name, vscode.CompletionItemKind.Variable);
+ clItem.sortText = '';
+ clItem.detail = symbol.type;
+ suggestNets.push(clItem);
+ }
+ }
+ return suggestNets;
+ }
+};
+
+const vhdlCompletionProvider = new VhdlCompletionProvider();
+
+export {
+ vhdlCompletionProvider
+};
\ No newline at end of file
diff --git a/src/function/lsp/linter/base.ts b/src/function/lsp/linter/base.ts
index 3e3771e..1b87c1d 100644
--- a/src/function/lsp/linter/base.ts
+++ b/src/function/lsp/linter/base.ts
@@ -1,12 +1,16 @@
import * as vscode from 'vscode';
+import { HdlLangID } from '../../../global/enum';
interface BaseLinter {
diagnostic: vscode.DiagnosticCollection;
lint(document: vscode.TextDocument): Promise;
+ remove(uri: vscode.Uri): Promise;
+ initialise(langID: HdlLangID): Promise;
}
interface BaseManager {
initialise(): Promise;
+ updateLinter(): Promise;
}
diff --git a/src/function/lsp/linter/default.ts b/src/function/lsp/linter/default.ts
index efb9505..63d4131 100644
--- a/src/function/lsp/linter/default.ts
+++ b/src/function/lsp/linter/default.ts
@@ -73,13 +73,8 @@ class DefaultVlogLinter implements BaseLinter {
}
public async initialise() {
- for (const doc of vscode.workspace.textDocuments) {
- if (isVerilogFile(doc.fileName)) {
- // TODO : check performance
- await this.lint(doc);
- }
- }
- LspOutput.report('finish initialization of default vlog linter', ReportType.Launch);
+ // move code to outer layer
+ return true;
}
}
@@ -149,13 +144,8 @@ class DefaultVHDLLinter implements BaseLinter {
}
public async initialise() {
- for (const doc of vscode.workspace.textDocuments) {
- if (isVhdlFile(doc.fileName)) {
- // TODO : check performance
- await this.lint(doc);
- }
- }
- LspOutput.report('finish initialization of default vlog linter', ReportType.Launch);
+ // move code to outer layer
+ return true;
}
}
diff --git a/src/function/lsp/linter/modelsim.ts b/src/function/lsp/linter/modelsim.ts
index a4510cf..36aaa99 100644
--- a/src/function/lsp/linter/modelsim.ts
+++ b/src/function/lsp/linter/modelsim.ts
@@ -51,10 +51,14 @@ class ModelsimLinter implements BaseLinter {
this.diagnostic.set(document.uri, diagnostics);
}
} else {
- LspOutput.report('linter is not available, please check prj.modelsim.install.path in your setting', ReportType.Error);
+ LspOutput.report('modelsim linter is not available, please check prj.modelsim.install.path in your setting!', ReportType.Error, true);
}
}
+ async remove(uri: vscode.Uri) {
+ this.diagnostic.delete(uri);
+ }
+
/**
* @param document
* @param stdout stdout from xvlog
@@ -62,21 +66,24 @@ class ModelsimLinter implements BaseLinter {
*/
private provideDiagnostics(document: vscode.TextDocument, stdout: string): vscode.Diagnostic[] {
const diagnostics = [];
- for (const line of stdout.split('\n')) {
+ for (const line of stdout.split(/\r?\n/g)) {
const tokens = line.split(/(Error|Warning).+?(?: *?(?:.+?(?:\\|\/))+.+?\((\d+?)\):|)(?: *?near "(.+?)":|)(?: *?\((.+?)\)|) +?(.+)/gm);
-
- const headerInfo = tokens[0];
+ const headerInfo = tokens[1];
if (headerInfo === 'Error') {
const errorLine = parseInt(tokens[2]) - 1;
const syntaxInfo = tokens[5];
- const range = this.makeCorrectRange(document, errorLine);
+ LspOutput.report(` line: ${errorLine}, info: ${syntaxInfo}`, ReportType.Run);
+
+ const range = this.makeCorrectRange(document, errorLine, syntaxInfo);
const diag = new vscode.Diagnostic(range, syntaxInfo, vscode.DiagnosticSeverity.Error);
diagnostics.push(diag);
- } else if (headerInfo == 'Warning') {
+ } else if (headerInfo === 'Warning') {
const errorLine = parseInt(tokens[2]) - 1;
const syntaxInfo = tokens[5];
- const range = this.makeCorrectRange(document, errorLine);
+ LspOutput.report(` line: ${errorLine}, info: ${syntaxInfo}`, ReportType.Run);
+
+ const range = this.makeCorrectRange(document, errorLine, syntaxInfo);
const diag = new vscode.Diagnostic(range, syntaxInfo, vscode.DiagnosticSeverity.Warning);
diagnostics.push(diag);
}
@@ -84,8 +91,32 @@ class ModelsimLinter implements BaseLinter {
return diagnostics;
}
- private makeCorrectRange(document: vscode.TextDocument, line: number): vscode.Range {
+ private makeCorrectRange(document: vscode.TextDocument, line: number, syntaxInfo: string): vscode.Range {
+ // extract all the words like 'adawwd' in a syntax info
+ const singleQuoteWords = syntaxInfo.match(/'([^']*)'/g);
+ if (singleQuoteWords && singleQuoteWords.length > 0) {
+ const targetWord = singleQuoteWords.map(val => val.replace(/'/g, ''))[0];
+ // find range of target word
+ const textLine = document.lineAt(line);
+ const text = textLine.text;
+ const startCharacter = text.indexOf(targetWord);
+ if (startCharacter > -1) {
+ const endCharacter = startCharacter + targetWord.length;
+ const range = new vscode.Range(
+ new vscode.Position(line, startCharacter),
+ new vscode.Position(line, endCharacter)
+ );
+ return range;
+ }
+ }
+
+ // else target the first word in the line
+ return this.makeCommonRange(document, line, syntaxInfo);
+ }
+
+ private makeCommonRange(document: vscode.TextDocument, line: number, syntaxInfo: string): vscode.Range {
const startPosition = new vscode.Position(line, 0);
+
const wordRange = document.getWordRangeAtPosition(startPosition, /[`_0-9a-zA-Z]+/);
if (wordRange) {
return wordRange;
@@ -107,11 +138,11 @@ class ModelsimLinter implements BaseLinter {
const fullExecutorName = opeParam.os === 'win32' ? executorName + '.exe' : executorName;
if (modelsimInstallPath.trim() === '' || !fs.existsSync(modelsimInstallPath)) {
- LspOutput.report(`User's modelsim Install Path ${modelsimInstallPath}, which is invalid. Use ${executorName} in default.`, ReportType.Warn);
+ LspOutput.report(`User's modelsim Install Path "${modelsimInstallPath}", which is invalid. Use ${executorName} in default.`, ReportType.Warn);
LspOutput.report('If you have doubts, check prj.modelsim.install.path in setting', ReportType.Warn);
return executorName;
} else {
- LspOutput.report(`User's modelsim Install Path ${modelsimInstallPath}, which is invalid`);
+ LspOutput.report(`User's modelsim Install Path "${modelsimInstallPath}", which is invalid`);
const executorPath = hdlPath.join(
hdlPath.toSlash(modelsimInstallPath),
@@ -131,23 +162,23 @@ class ModelsimLinter implements BaseLinter {
}
const { stderr } = await easyExec(executorPath, []);
if (stderr.length === 0) {
- this.executableInvokeNameMap.set(langID, undefined);
- LspOutput.report(`fail to execute ${executorPath}! Reason: ${stderr}`, ReportType.Error);
- return false;
- } else {
this.executableInvokeNameMap.set(langID, executorPath);
LspOutput.report(`success to verify ${executorPath}, linter from modelsim is ready to go!`, ReportType.Launch);
return true;
+ } else {
+ this.executableInvokeNameMap.set(langID, undefined);
+ LspOutput.report(`fail to execute ${executorPath}! Reason: ${stderr}`, ReportType.Error, true);
+ return false;
}
}
- public initialise(langID: HdlLangID) {
+ public async initialise(langID: HdlLangID): Promise {
const executorPath = this.getExecutableFilePath(langID);
- this.setExecutableFilePath(executorPath, langID);
+ return this.setExecutableFilePath(executorPath, langID);
}
}
-const modelsimLinter = new ModelsimLinter()
+const modelsimLinter = new ModelsimLinter();
export {
modelsimLinter,
diff --git a/src/function/lsp/linter/verilator.ts b/src/function/lsp/linter/verilator.ts
index b51a953..656af79 100644
--- a/src/function/lsp/linter/verilator.ts
+++ b/src/function/lsp/linter/verilator.ts
@@ -43,47 +43,59 @@ class VerilatorLinter implements BaseLinter {
const args = [filePath, ...linterArgs];
const executor = this.executableInvokeNameMap.get(langID);
if (executor !== undefined) {
- const { stdout } = await easyExec(executor, args);
- if (stdout.length > 0) {
- const diagnostics = this.provideDiagnostics(document, stdout);
+ const { stderr } = await easyExec(executor, args);
+ if (stderr.length > 0) {
+ const diagnostics = this.provideDiagnostics(document, stderr);
this.diagnostic.set(document.uri, diagnostics);
}
} else {
- LspOutput.report('linter is not available, please check prj.verilator.install.path in your setting', ReportType.Error);
+ LspOutput.report('verilator linter is not available, please check prj.verilator.install.path in your setting', ReportType.Error, true);
}
}
+ async remove(uri: vscode.Uri) {
+ this.diagnostic.delete(uri);
+ }
+
/**
* @param document
* @param stdout stdout from xvlog
* @returns { vscode.Diagnostic[] } linter info
*/
- private provideDiagnostics(document: vscode.TextDocument, stdout: string): vscode.Diagnostic[] {
+ private provideDiagnostics(document: vscode.TextDocument, stderr: string): vscode.Diagnostic[] {
const diagnostics = [];
- for (const line of stdout.split('\n')) {
- const tokens = line.split(/(Error|Warning).+?(?: *?(?:.+?(?:\\|\/))+.+?\((\d+?)\):|)(?: *?near "(.+?)":|)(?: *?\((.+?)\)|) +?(.+)/gm);
- // TODO : make parser of output info from verilator
+ for (let line of stderr.split(/\r?\n/g)) {
+ if (!line.startsWith('%')) {
+ continue;
+ } else {
+ line = line.substring(1);
+ }
+
+ const tokens = line.split(':');
+ if (tokens.length < 3) {
+ continue;
+ }
+ const header = tokens[0].toLowerCase();
+ const fileName = tokens[1];
+ const lineNo = parseInt(tokens[2]) - 1;
+ const characterNo = parseInt(tokens[3]) - 1;
+ const syntaxInfo = tokens[4];
- const headerInfo = tokens[0];
- if (headerInfo === 'Error') {
- const errorLine = parseInt(tokens[2]) - 1;
- const syntaxInfo = tokens[5];
- const range = this.makeCorrectRange(document, errorLine);
+ if (header.startsWith('warning')) {
+ const range = this.makeCorrectRange(document, lineNo, characterNo);
+ const diag = new vscode.Diagnostic(range, syntaxInfo, vscode.DiagnosticSeverity.Warning);
+ diagnostics.push(diag);
+ } else if (header.startsWith('error')) {
+ const range = this.makeCorrectRange(document, lineNo, characterNo);
const diag = new vscode.Diagnostic(range, syntaxInfo, vscode.DiagnosticSeverity.Error);
diagnostics.push(diag);
- } else if (headerInfo == 'Warning') {
- const errorLine = parseInt(tokens[2]) - 1;
- const syntaxInfo = tokens[5];
- const range = this.makeCorrectRange(document, errorLine);
- const diag = new vscode.Diagnostic(range, syntaxInfo, vscode.DiagnosticSeverity.Warning);
- diagnostics.push(diag);
}
}
return diagnostics;
}
- private makeCorrectRange(document: vscode.TextDocument, line: number): vscode.Range {
- const startPosition = new vscode.Position(line, 0);
+ private makeCorrectRange(document: vscode.TextDocument, line: number, character: number): vscode.Range {
+ const startPosition = new vscode.Position(line, character);
const wordRange = document.getWordRangeAtPosition(startPosition, /[`_0-9a-zA-Z]+/);
if (wordRange) {
return wordRange;
@@ -129,19 +141,20 @@ class VerilatorLinter implements BaseLinter {
}
const { stderr } = await easyExec(executorPath, []);
if (stderr.length === 0) {
- this.executableInvokeNameMap.set(langID, undefined);
- LspOutput.report(`fail to execute ${executorPath}! Reason: ${stderr}`, ReportType.Error);
- return false;
- } else {
this.executableInvokeNameMap.set(langID, executorPath);
LspOutput.report(`success to verify ${executorPath}, linter from verilator is ready to go!`, ReportType.Launch);
return true;
+ } else {
+ this.executableInvokeNameMap.set(langID, undefined);
+ LspOutput.report(`fail to execute ${executorPath}! Reason: ${stderr}`, ReportType.Error, true);
+
+ return false;
}
}
- public initialise(langID: HdlLangID) {
+ public async initialise(langID: HdlLangID): Promise {
const executorPath = this.getExecutableFilePath(langID);
- this.setExecutableFilePath(executorPath, langID);
+ return this.setExecutableFilePath(executorPath, langID);
}
}
diff --git a/src/function/lsp/linter/vhdl.ts b/src/function/lsp/linter/vhdl.ts
index ede90f5..1bec2c2 100644
--- a/src/function/lsp/linter/vhdl.ts
+++ b/src/function/lsp/linter/vhdl.ts
@@ -5,6 +5,7 @@ import { BaseLinter, BaseManager } from './base';
import { defaultVlogLinter } from './default';
import { modelsimLinter } from './modelsim';
import { vivadoLinter } from './vivado';
+import { hdlFile, hdlPath } from '../../../hdlFs';
class VhdlLinterManager implements BaseManager {
currentLinter: BaseLinter | undefined;
@@ -17,21 +18,37 @@ class VhdlLinterManager implements BaseManager {
this.activateList.set('default', false);
this.activateLinterName = 'default';
- this.updateLinter();
-
// update when user's config is changed
vscode.workspace.onDidChangeConfiguration(() => {
const diagnostor = this.getUserDiagnostorSelection();
const lastDiagnostor = this.activateLinterName;
if (diagnostor !== lastDiagnostor) {
- LspOutput.report(`[vhdl lsp manager] detect linter setting changes, switch ${lastDiagnostor} to ${diagnostor}.`, );
+ LspOutput.report(` detect linter setting changes, switch ${lastDiagnostor} to ${diagnostor}.`, );
this.updateLinter();
}
});
}
async initialise(): Promise {
-
+ const success = await this.updateLinter();
+ if (!success) {
+ return;
+ }
+ for (const doc of vscode.workspace.textDocuments) {
+ const fileName = hdlPath.toSlash(doc.fileName);
+ if (hdlFile.isVhdlFile(fileName)) {
+ await this.lint(doc);
+ }
+ }
+ LspOutput.report(' finish initialization of vhdl linter. Linter name: ' + this.activateLinterName, ReportType.Launch);
+ }
+
+ async lint(document: vscode.TextDocument) {
+ await this.currentLinter?.lint(document);
+ }
+
+ async remove(uri: vscode.Uri): Promise {
+ this.currentLinter?.remove(uri);
}
public getUserDiagnostorSelection() {
@@ -40,53 +57,59 @@ class VhdlLinterManager implements BaseManager {
return diagnostor;
}
- public updateLinter() {
+ public async updateLinter(): Promise {
const diagnostor = this.getUserDiagnostorSelection();
switch (diagnostor) {
- case 'vivado': this.activateVivado(); break;
- case 'modelsim': this.activateModelsim(); break;
- case 'default': this.activateDefault(); break;
- case default: this.activateDefault(); break;
+ case 'vivado': return this.activateVivado();
+ case 'modelsim': return this.activateModelsim();
+ case 'default': return this.activateDefault();
+ default: return this.activateDefault();
}
}
- public activateVivado() {
+ public async activateVivado(): Promise {
const selectedLinter = vivadoLinter;
+ let launch = true;
if (this.activateList.get('vivado') === false) {
- selectedLinter.initialise(HdlLangID.Verilog);
+ launch = await selectedLinter.initialise(HdlLangID.Verilog);
this.activateList.set('vivado', true);
- LspOutput.report('[vhdl lsp manager] vivado linter has been activated', ReportType.Info);
+ LspOutput.report(' vivado linter has been activated', ReportType.Info);
}
this.currentLinter = selectedLinter;
this.activateLinterName = 'vivado';
+ return launch;
}
- public activateModelsim() {
+ public async activateModelsim(): Promise {
const selectedLinter = modelsimLinter;
+ let launch = true;
if (this.activateList.get('modelsim') === false) {
- selectedLinter.initialise(HdlLangID.Verilog);
+ launch = await selectedLinter.initialise(HdlLangID.Verilog);
this.activateList.set('modelsim', true);
- LspOutput.report('[vhdl lsp manager] modelsim linter has been activated', ReportType.Info);
+ LspOutput.report(' modelsim linter has been activated', ReportType.Info);
}
this.currentLinter = selectedLinter;
this.activateLinterName = 'modelsim';
+ return launch;
}
- public activateDefault() {
+ public async activateDefault(): Promise {
const selectedLinter = defaultVlogLinter;
+ let launch = true;
if (this.activateList.get('default') === false) {
this.activateList.set('default', true);
- LspOutput.report('[vhdl lsp manager] default build-in linter has been activated', ReportType.Info);
+ LspOutput.report(' default build-in linter has been activated', ReportType.Info);
}
this.currentLinter = selectedLinter;
this.activateLinterName = 'default';
+ return launch;
}
}
diff --git a/src/function/lsp/linter/vivado.ts b/src/function/lsp/linter/vivado.ts
index f48cf9a..fda808c 100644
--- a/src/function/lsp/linter/vivado.ts
+++ b/src/function/lsp/linter/vivado.ts
@@ -54,10 +54,14 @@ class VivadoLinter implements BaseLinter {
this.diagnostic.set(document.uri, diagnostics);
}
} else {
- LspOutput.report('linter is not available, please check prj.vivado.install.path in your setting', ReportType.Error);
+ LspOutput.report('vivado linter is not available, please check prj.vivado.install.path in your setting', ReportType.Error, true);
}
}
+ async remove(uri: vscode.Uri) {
+ this.diagnostic.delete(uri);
+ }
+
/**
* @param document
* @param stdout stdout from xvlog
@@ -65,7 +69,7 @@ class VivadoLinter implements BaseLinter {
*/
private provideDiagnostics(document: vscode.TextDocument, stdout: string): vscode.Diagnostic[] {
const diagnostics = [];
- for (const line of stdout.split('\n')) {
+ for (const line of stdout.split(/\r?\n/g)) {
const tokens = line.split(/:?\s*(?:\[|\])\s*/);
const headerInfo = tokens[0];
// const standardInfo = tokens[1];
@@ -73,8 +77,10 @@ class VivadoLinter implements BaseLinter {
const parsedPath = tokens[3];
if (headerInfo === 'ERROR') {
const errorInfos = parsedPath.split(':');
- const errorLine = parseInt(errorInfos[errorInfos.length - 1]);
- const range = this.makeCorrectRange(document, errorLine);
+ const errorLine = Math.max(parseInt(errorInfos[errorInfos.length - 1]) - 1, 0);
+ LspOutput.report(` line: ${errorLine}, info: ${syntaxInfo}`, ReportType.Run);
+
+ const range = this.makeCorrectRange(document, errorLine, syntaxInfo);
const diag = new vscode.Diagnostic(range, syntaxInfo, vscode.DiagnosticSeverity.Error);
diagnostics.push(diag);
}
@@ -82,8 +88,32 @@ class VivadoLinter implements BaseLinter {
return diagnostics;
}
- private makeCorrectRange(document: vscode.TextDocument, line: number): vscode.Range {
+ private makeCorrectRange(document: vscode.TextDocument, line: number, syntaxInfo: string): vscode.Range {
+ // extract all the words like 'adawwd' in a syntax info
+ const singleQuoteWords = syntaxInfo.match(/'([^']*)'/g);
+ if (singleQuoteWords && singleQuoteWords.length > 0) {
+ const targetWord = singleQuoteWords.map(val => val.replace(/'/g, ''))[0];
+ // find range of target word
+ const textLine = document.lineAt(line);
+ const text = textLine.text;
+ const startCharacter = text.indexOf(targetWord);
+ if (startCharacter > -1) {
+ const endCharacter = startCharacter + targetWord.length;
+ const range = new vscode.Range(
+ new vscode.Position(line, startCharacter),
+ new vscode.Position(line, endCharacter)
+ );
+ return range;
+ }
+ }
+
+ // else target the first word in the line
+ return this.makeCommonRange(document, line, syntaxInfo);
+ }
+
+ private makeCommonRange(document: vscode.TextDocument, line: number, syntaxInfo: string): vscode.Range {
const startPosition = new vscode.Position(line, 0);
+
const wordRange = document.getWordRangeAtPosition(startPosition, /[`_0-9a-zA-Z]+/);
if (wordRange) {
return wordRange;
@@ -105,11 +135,11 @@ class VivadoLinter implements BaseLinter {
const fullExecutorName = opeParam.os === 'win32' ? executorName + '.bat' : executorName;
if (vivadoInstallPath.trim() === '' || !fs.existsSync(vivadoInstallPath)) {
- LspOutput.report(`User's Vivado Install Path ${vivadoInstallPath}, which is invalid. Use ${executorName} in default.`, ReportType.Warn);
+ LspOutput.report(`User's Vivado Install Path "${vivadoInstallPath}", which is invalid. Use ${executorName} in default.`, ReportType.Warn);
LspOutput.report('If you have doubts, check prj.vivado.install.path in setting', ReportType.Warn);
return executorName;
} else {
- LspOutput.report(`User's Vivado Install Path ${vivadoInstallPath}, which is invalid`);
+ LspOutput.report(`User's Vivado Install Path "${vivadoInstallPath}", which is invalid`);
const executorPath = hdlPath.join(
hdlPath.toSlash(vivadoInstallPath),
@@ -129,19 +159,19 @@ class VivadoLinter implements BaseLinter {
}
const { stderr } = await easyExec(executorPath, []);
if (stderr.length === 0) {
- this.executableInvokeNameMap.set(langID, undefined);
- LspOutput.report(`fail to execute ${executorPath}! Reason: ${stderr}`, ReportType.Error);
- return false;
- } else {
this.executableInvokeNameMap.set(langID, executorPath);
LspOutput.report(`success to verify ${executorPath}, linter from vivado is ready to go!`, ReportType.Launch);
return true;
+ } else {
+ this.executableInvokeNameMap.set(langID, undefined);
+ LspOutput.report(`fail to execute ${executorPath}! Reason: ${stderr}`, ReportType.Error, true);
+ return false;
}
}
- public initialise(langID: HdlLangID) {
+ public async initialise(langID: HdlLangID): Promise {
const executorPath = this.getExecutableFilePath(langID);
- this.setExecutableFilePath(executorPath, langID);
+ return this.setExecutableFilePath(executorPath, langID);
}
}
diff --git a/src/function/lsp/linter/vlog.ts b/src/function/lsp/linter/vlog.ts
index 4142176..5c61e42 100644
--- a/src/function/lsp/linter/vlog.ts
+++ b/src/function/lsp/linter/vlog.ts
@@ -5,6 +5,7 @@ import { BaseLinter, BaseManager } from './base';
import { defaultVlogLinter } from './default';
import { modelsimLinter } from './modelsim';
import { vivadoLinter } from './vivado';
+import { hdlFile, hdlPath } from '../../../hdlFs';
class VlogLinterManager implements BaseManager {
currentLinter: BaseLinter | undefined;
@@ -17,21 +18,39 @@ class VlogLinterManager implements BaseManager {
this.activateList.set('default', false);
this.activateLinterName = 'default';
- this.updateLinter();
-
// update when user's config is changed
vscode.workspace.onDidChangeConfiguration(() => {
const diagnostor = this.getUserDiagnostorSelection();
const lastDiagnostor = this.activateLinterName;
if (diagnostor !== lastDiagnostor) {
- LspOutput.report(`detect linter setting changes, switch ${lastDiagnostor} to ${diagnostor}.`, );
+ LspOutput.report(` detect linter setting changes, switch ${lastDiagnostor} to ${diagnostor}.`, );
this.updateLinter();
}
});
+
}
async initialise(): Promise {
-
+ const success = await this.updateLinter();
+ if (!success) {
+ return;
+ }
+
+ for (const doc of vscode.workspace.textDocuments) {
+ const fileName = hdlPath.toSlash(doc.fileName);
+ if (hdlFile.isVerilogFile(fileName)) {
+ await this.lint(doc);
+ }
+ }
+ LspOutput.report(' finish initialization of vlog linter. Linter name: ' + this.activateLinterName, ReportType.Launch);
+ }
+
+ async lint(document: vscode.TextDocument) {
+ await this.currentLinter?.lint(document);
+ }
+
+ async remove(uri: vscode.Uri): Promise {
+ this.currentLinter?.remove(uri);
}
public getUserDiagnostorSelection() {
@@ -40,53 +59,59 @@ class VlogLinterManager implements BaseManager {
return diagnostor;
}
- public updateLinter() {
+ public async updateLinter() {
const diagnostor = this.getUserDiagnostorSelection();
switch (diagnostor) {
- case 'vivado': this.activateVivado(); break;
- case 'modelsim': this.activateModelsim(); break;
- case 'default': this.activateDefault(); break;
- case default: this.activateDefault(); break;
- }
+ case 'vivado': return this.activateVivado();
+ case 'modelsim': return this.activateModelsim();
+ case 'default': return this.activateDefault();
+ default: return this.activateDefault();
+ }
}
- public activateVivado() {
+ public async activateVivado(): Promise {
const selectedLinter = vivadoLinter;
+ let launch = true;
if (this.activateList.get('vivado') === false) {
- selectedLinter.initialise(HdlLangID.Verilog);
+ launch = await selectedLinter.initialise(HdlLangID.Verilog);
this.activateList.set('vivado', true);
- LspOutput.report('vivado linter has been activated', ReportType.Info);
+ LspOutput.report(' vivado linter has been activated', ReportType.Info);
}
this.currentLinter = selectedLinter;
this.activateLinterName = 'vivado';
+ return launch;
}
- public activateModelsim() {
+ public async activateModelsim(): Promise {
const selectedLinter = modelsimLinter;
+ let launch = true;
if (this.activateList.get('modelsim') === false) {
- selectedLinter.initialise(HdlLangID.Verilog);
+ launch = await selectedLinter.initialise(HdlLangID.Verilog);
this.activateList.set('modelsim', true);
- LspOutput.report('modelsim linter has been activated', ReportType.Info);
+ LspOutput.report(' modelsim linter has been activated', ReportType.Info);
}
this.currentLinter = selectedLinter;
this.activateLinterName = 'modelsim';
+ return launch;
}
- public activateDefault() {
+ public async activateDefault(): Promise {
const selectedLinter = defaultVlogLinter;
+ let launch = true;
if (this.activateList.get('default') === false) {
this.activateList.set('default', true);
- LspOutput.report('default build-in linter has been activated', ReportType.Info);
+ LspOutput.report(' default build-in linter has been activated', ReportType.Info);
}
this.currentLinter = selectedLinter;
this.activateLinterName = 'default';
+ return launch;
}
}
diff --git a/src/monitor/event.ts b/src/monitor/event.ts
index 4f93d3f..28b397f 100644
--- a/src/monitor/event.ts
+++ b/src/monitor/event.ts
@@ -12,9 +12,9 @@ import { hdlParam, HdlSymbol } from '../hdlParser';
import { prjManage } from '../manager';
import { libManage } from '../manager/lib';
import type { HdlMonitor } from './index';
-import { ToolChainType } from '../global/enum';
+import { HdlLangID, ToolChainType } from '../global/enum';
import { hdlSymbolStorage } from '../function/lsp/core';
-import { vlogLinter } from '../function/lsp/linter';
+import { vlogLinterManager, vhdlLinterManager } from '../function/lsp/linter';
import { isVerilogFile } from '../hdlFs/file';
enum Event {
@@ -98,7 +98,12 @@ class HdlAction extends BaseAction {
}
const uri = vscode.Uri.file(path);
- vlogLinter.remove(uri);
+ const langID = hdlFile.getLanguageId(path);
+ if (langID === HdlLangID.Verilog) {
+ vlogLinterManager.remove(uri);
+ } else if (langID === HdlLangID.Vhdl) {
+ vhdlLinterManager.remove(uri);
+ }
}
async unlinkDir(path: string, m: HdlMonitor): Promise {
@@ -128,10 +133,16 @@ class HdlAction extends BaseAction {
}
async updateLinter(path: string) {
- if (isVerilogFile(path)) {
- const uri = vscode.Uri.file(path);
- const document = await vscode.workspace.openTextDocument(uri);
- vlogLinter.lint(document);
+ const uri = vscode.Uri.file(path);
+ const document = await vscode.workspace.openTextDocument(uri);
+ const langID = hdlFile.getLanguageId(path);
+
+ if (langID === HdlLangID.Verilog) {
+ vlogLinterManager.lint(document);
+ } else if (langID === HdlLangID.Vhdl) {
+ vhdlLinterManager.lint(document);
+ } else if (langID === HdlLangID.SystemVerilog) {
+ // TODO
}
}
diff --git a/syntaxes/digital-ide-output.json b/syntaxes/digital-ide-output.json
index 2631569..7945dea 100644
--- a/syntaxes/digital-ide-output.json
+++ b/syntaxes/digital-ide-output.json
@@ -71,6 +71,18 @@
}
}
},
+ {
+ "name": "digital-ide.Launch",
+ "match": "(\\[Launch - (.*)\\])([\\s\\S]*)",
+ "captures": {
+ "1": {
+ "name": "keyword.launch-token"
+ },
+ "2": {
+ "name": "string"
+ }
+ }
+ },
{
"name": "string.quoted.double",
"begin": "\"",
diff --git a/syntaxes/vhdl.json b/syntaxes/vhdl.tmLanguage.json
similarity index 100%
rename from syntaxes/vhdl.json
rename to syntaxes/vhdl.tmLanguage.json
diff --git a/syntaxes/vvp.tmLanguage.json b/syntaxes/vvp.tmLanguage.json
new file mode 100644
index 0000000..8f2d125
--- /dev/null
+++ b/syntaxes/vvp.tmLanguage.json
@@ -0,0 +1,361 @@
+{
+ "fileTypes": [
+ "v",
+ "vh"
+ ],
+ "keyEquivalent": "^~V",
+ "name": "Verilog",
+ "patterns": [
+ {
+ "include": "#comments"
+ },
+ {
+ "include": "#module_pattern"
+ },
+ {
+ "include": "#keywords"
+ },
+ {
+ "include": "#constants"
+ },
+ {
+ "include": "#strings"
+ },
+ {
+ "include": "#operators"
+ },
+ {
+ "include": "#macro_definition"
+ },
+ {
+ "include": "#macro_quote"
+ },
+ {
+ "include": "#common_variable"
+ }
+ ],
+ "repository": {
+ "comments": {
+ "patterns": [
+ {
+ "begin": "(^[ \\t]+)?(?=#)",
+ "beginCaptures": {
+ "1": {
+ "name": "punctuation.whitespace.comment.leading.verilog"
+ }
+ },
+ "end": "(?!\\G)",
+ "patterns": [
+ {
+ "begin": "#",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.definition.comment.verilog"
+ }
+ },
+ "end": "\\n",
+ "name": "comment.line.double-slash.verilog"
+ }
+ ]
+ },
+ {
+ "begin": "/\\*",
+ "end": "\\*/",
+ "name": "comment.block.c-style.verilog"
+ }
+ ]
+ },
+ "constants": {
+ "patterns": [
+ {
+ "match": "\\b[0-9]+'[bBoOdDhH][a-fA-F0-9_xXzZ]+\\b",
+ "name": "constant.numeric.sized_integer.verilog"
+ },
+ {
+ "captures": {
+ "1": {
+ "name": "constant.numeric.integer.verilog"
+ },
+ "2": {
+ "name": "punctuation.separator.range.verilog"
+ },
+ "3": {
+ "name": "constant.numeric.integer.verilog"
+ }
+ },
+ "match": "\\b(\\d+)(:)(\\d+)\\b",
+ "name": "meta.block.numeric.range.verilog"
+ },
+ {
+ "match": "\\b\\d+(?i:e\\d+)?\\b",
+ "name": "constant.numeric.integer.verilog"
+ },
+ {
+ "match": "\\b\\d+\\.\\d+(?i:e\\d+)?\\b",
+ "name": "constant.numeric.real.verilog"
+ },
+ {
+ "match": "#\\d+",
+ "name": "constant.numeric.delay.verilog"
+ },
+ {
+ "match": "\\b[01xXzZ]+\\b",
+ "name": "constant.numeric.logic.verilog"
+ }
+ ]
+ },
+ "instantiation_patterns": {
+ "patterns": [
+ {
+ "include": "#keywords"
+ },
+ {
+ "begin": "^\\s*([a-zA-Z][a-zA-Z0-9_]*)\\s+([a-zA-Z][a-zA-Z0-9_]*)(?)=?|(!|=)?==?|!|&&?|\\|\\|?|\\^?~|~\\^?",
+ "name": "keyword.operator.verilog"
+ }
+ ]
+ },
+ "parenthetical_list": {
+ "patterns": [
+ {
+ "begin": "\\(",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.section.list.verilog"
+ }
+ },
+ "end": "\\)",
+ "endCaptures": {
+ "0": {
+ "name": "punctuation.section.list.verilog"
+ }
+ },
+ "name": "support.block.parenthetical_list.verilog",
+ "patterns": [
+ {
+ "include": "#parenthetical_list"
+ },
+ {
+ "include": "#comments"
+ },
+ {
+ "include": "#keywords"
+ },
+ {
+ "include": "#constants"
+ },
+ {
+ "include": "#strings"
+ },
+ {
+ "include": "#position_ports"
+ },
+ {
+ "include": "#macro_quote"
+ },
+ {
+ "include": "#common_variable"
+ }
+ ]
+ }
+ ]
+ },
+ "position_ports": {
+ "patterns": [
+ {
+ "match": "\\.[a-zA-Z_][a-zA-Z_0-9]*",
+ "name": "variable.inst.port.verilog"
+ }
+ ]
+ },
+ "strings": {
+ "patterns": [
+ {
+ "begin": "\"",
+ "end": "\"",
+ "name": "string.quoted.double.verilog",
+ "patterns": [
+ {
+ "match": "\\\\.",
+ "name": "constant.character.escape.verilog"
+ }
+ ]
+ }
+ ]
+ },
+ "macro_definition": {
+ "patterns": [
+ {
+ "match": "(?<=`define\\s)\\w+",
+ "name": "support.function.macro.definition.verilog"
+ }
+ ]
+ },
+ "macro_quote": {
+ "patterns": [
+ {
+ "match": "`[a-zA-Z_][a-zA-Z_0-9]*",
+ "name": "support.function.macro.quote.verilog"
+ }
+ ]
+ },
+ "common_variable": {
+ "patterns": [
+ {
+ "match": "[a-zA-Z_][a-zA-Z_0-9]*",
+ "name": "variable.other.constant.verilog"
+ }
+ ]
+ }
+ },
+ "scopeName": "source.vvp",
+ "uuid": "7F4396B3-A33E-44F0-8502-98CA6C25971F"
+}
\ No newline at end of file
diff --git a/test/vlogFast.js b/test/vlogFast.js
new file mode 100644
index 0000000..8c53606
--- /dev/null
+++ b/test/vlogFast.js
@@ -0,0 +1,8 @@
+const { vlogFast } = require('../resources/hdlParser');
+
+const testFile = 'c:/Users/11934/Project/Digital-IDE/Digital-Test/Verilog/dependence_test/parent.v';
+
+(async () => {
+ const fast = vlogFast(testFile);
+ console.log(JSON.stringify(fast, null, ' '));
+})();
\ No newline at end of file