finish vlog completion | definition | hover | docSymbol | formatter
This commit is contained in:
parent
b16f9bf104
commit
4fd79de4e4
199
format.json
199
format.json
@ -1,199 +0,0 @@
|
|||||||
{
|
|
||||||
"content": {
|
|
||||||
"modules": [
|
|
||||||
{
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"instparams": null,
|
|
||||||
"instports": {
|
|
||||||
"end": {
|
|
||||||
"character": 10,
|
|
||||||
"line": 21
|
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"character": 4,
|
|
||||||
"line": 18
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": "dependence_1",
|
|
||||||
"range": {
|
|
||||||
"end": {
|
|
||||||
"character": 0,
|
|
||||||
"line": 22
|
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"character": 13,
|
|
||||||
"line": 17
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "dependence_1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"instparams": null,
|
|
||||||
"instports": {
|
|
||||||
"end": {
|
|
||||||
"character": 9,
|
|
||||||
"line": 28
|
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"character": 4,
|
|
||||||
"line": 25
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": "dependence_2",
|
|
||||||
"range": {
|
|
||||||
"end": {
|
|
||||||
"character": 0,
|
|
||||||
"line": 29
|
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"character": 13,
|
|
||||||
"line": 24
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "dependence_2"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Main",
|
|
||||||
"params": [],
|
|
||||||
"ports": [
|
|
||||||
{
|
|
||||||
"name": "a",
|
|
||||||
"range": {
|
|
||||||
"end": {
|
|
||||||
"character": 17,
|
|
||||||
"line": 11
|
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"character": 16,
|
|
||||||
"line": 11
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "input",
|
|
||||||
"width": "[3:0]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "b",
|
|
||||||
"range": {
|
|
||||||
"end": {
|
|
||||||
"character": 17,
|
|
||||||
"line": 12
|
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"character": 16,
|
|
||||||
"line": 12
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "input",
|
|
||||||
"width": "[2:0]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "c",
|
|
||||||
"range": {
|
|
||||||
"end": {
|
|
||||||
"character": 11,
|
|
||||||
"line": 13
|
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"character": 10,
|
|
||||||
"line": 13
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "input",
|
|
||||||
"width": "Unknown"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Qus",
|
|
||||||
"range": {
|
|
||||||
"end": {
|
|
||||||
"character": 14,
|
|
||||||
"line": 14
|
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"character": 11,
|
|
||||||
"line": 14
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "output",
|
|
||||||
"width": "Unknown"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Qs",
|
|
||||||
"range": {
|
|
||||||
"end": {
|
|
||||||
"character": 18,
|
|
||||||
"line": 14
|
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"character": 16,
|
|
||||||
"line": 14
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "output",
|
|
||||||
"width": "Unknown"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "`main_o",
|
|
||||||
"range": {
|
|
||||||
"end": {
|
|
||||||
"character": 27,
|
|
||||||
"line": 14
|
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"character": 20,
|
|
||||||
"line": 14
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "output",
|
|
||||||
"width": "Unknown"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"range": {
|
|
||||||
"end": {
|
|
||||||
"character": 0,
|
|
||||||
"line": 31
|
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"character": 0,
|
|
||||||
"line": 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"languageId": "verilog",
|
|
||||||
"macro": {
|
|
||||||
"defines": [
|
|
||||||
{
|
|
||||||
"name": "main_o",
|
|
||||||
"range": {
|
|
||||||
"end": {
|
|
||||||
"character": 19,
|
|
||||||
"line": 9
|
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"character": 1,
|
|
||||||
"line": 9
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"value": "out"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"includes": [
|
|
||||||
{
|
|
||||||
"path": "child_1.v",
|
|
||||||
"range": {
|
|
||||||
"end": {
|
|
||||||
"character": 9,
|
|
||||||
"line": 8
|
|
||||||
},
|
|
||||||
"start": {
|
|
||||||
"character": 1,
|
|
||||||
"line": 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"invalid": []
|
|
||||||
}
|
|
||||||
}
|
|
11
package-lock.json
generated
11
package-lock.json
generated
@ -13,6 +13,7 @@
|
|||||||
"showdown": "^2.1.0",
|
"showdown": "^2.1.0",
|
||||||
"state-machine-cat": "^9.2.5",
|
"state-machine-cat": "^9.2.5",
|
||||||
"temp": "^0.9.4",
|
"temp": "^0.9.4",
|
||||||
|
"vscode-textmate": "^9.0.0",
|
||||||
"wavedrom": "^2.9.1"
|
"wavedrom": "^2.9.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -2829,6 +2830,11 @@
|
|||||||
"integrity": "sha512-W+1+N/hdzLpQZEcvz79n2IgUE9pfx6JLdHh3Kh8RGvLL8P1LdJVQmi2OsDcLdY4QVID4OUy+FPelyerX0nJxIQ==",
|
"integrity": "sha512-W+1+N/hdzLpQZEcvz79n2IgUE9pfx6JLdHh3Kh8RGvLL8P1LdJVQmi2OsDcLdY4QVID4OUy+FPelyerX0nJxIQ==",
|
||||||
"deprecated": "no longer supported"
|
"deprecated": "no longer supported"
|
||||||
},
|
},
|
||||||
|
"node_modules/vscode-textmate": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg=="
|
||||||
|
},
|
||||||
"node_modules/wavedrom": {
|
"node_modules/wavedrom": {
|
||||||
"version": "2.9.1",
|
"version": "2.9.1",
|
||||||
"resolved": "https://registry.npmmirror.com/wavedrom/-/wavedrom-2.9.1.tgz",
|
"resolved": "https://registry.npmmirror.com/wavedrom/-/wavedrom-2.9.1.tgz",
|
||||||
@ -5216,6 +5222,11 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/viz.js/-/viz.js-1.8.2.tgz",
|
"resolved": "https://registry.npmmirror.com/viz.js/-/viz.js-1.8.2.tgz",
|
||||||
"integrity": "sha512-W+1+N/hdzLpQZEcvz79n2IgUE9pfx6JLdHh3Kh8RGvLL8P1LdJVQmi2OsDcLdY4QVID4OUy+FPelyerX0nJxIQ=="
|
"integrity": "sha512-W+1+N/hdzLpQZEcvz79n2IgUE9pfx6JLdHh3Kh8RGvLL8P1LdJVQmi2OsDcLdY4QVID4OUy+FPelyerX0nJxIQ=="
|
||||||
},
|
},
|
||||||
|
"vscode-textmate": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg=="
|
||||||
|
},
|
||||||
"wavedrom": {
|
"wavedrom": {
|
||||||
"version": "2.9.1",
|
"version": "2.9.1",
|
||||||
"resolved": "https://registry.npmmirror.com/wavedrom/-/wavedrom-2.9.1.tgz",
|
"resolved": "https://registry.npmmirror.com/wavedrom/-/wavedrom-2.9.1.tgz",
|
||||||
|
46
package.json
46
package.json
@ -129,6 +129,51 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "run the simulation command in terminal instead of output"
|
"description": "run the simulation command in terminal instead of output"
|
||||||
|
},
|
||||||
|
"function.lsp.formatter.vlog.default.style": {
|
||||||
|
"scope": "window",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"kr",
|
||||||
|
"ansi",
|
||||||
|
"gnu"
|
||||||
|
],
|
||||||
|
"default": "kr",
|
||||||
|
"description": "Select the verilog and systemverilog formatter style."
|
||||||
|
},
|
||||||
|
"function.lsp.formatter.vlog.default.args": {
|
||||||
|
"scope": "window",
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "Add verilog formatter arguments here (like istyle)."
|
||||||
|
},
|
||||||
|
"function.lsp.formatter.vhdl.default.keyword-case": {
|
||||||
|
"description": "Keyword case",
|
||||||
|
"type": "string",
|
||||||
|
"default": "LowerCase",
|
||||||
|
"enum": [
|
||||||
|
"LowerCase",
|
||||||
|
"UpperCase"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"function.lsp.formatter.vhdl.default.align-comments": {
|
||||||
|
"description": "Align comments",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"function.lsp.formatter.vhdl.default.type-name-case": {
|
||||||
|
"description": "Type name case",
|
||||||
|
"type": "string",
|
||||||
|
"default": "LowerCase",
|
||||||
|
"enum": [
|
||||||
|
"LowerCase",
|
||||||
|
"UpperCase"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"function.lsp.formatter.vhdl.default.indentation": {
|
||||||
|
"description": "Indentation",
|
||||||
|
"type": "number",
|
||||||
|
"default": 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -749,6 +794,7 @@
|
|||||||
"showdown": "^2.1.0",
|
"showdown": "^2.1.0",
|
||||||
"state-machine-cat": "^9.2.5",
|
"state-machine-cat": "^9.2.5",
|
||||||
"temp": "^0.9.4",
|
"temp": "^0.9.4",
|
||||||
|
"vscode-textmate": "^9.0.0",
|
||||||
"wavedrom": "^2.9.1"
|
"wavedrom": "^2.9.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
8
resources/formatter/index.d.ts
vendored
Normal file
8
resources/formatter/index.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
|
|
||||||
|
declare module formatterProvider {
|
||||||
|
export const hdlFormatterProvider: vscode.DocumentFormattingEditProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
export = formatterProvider;
|
137
resources/formatter/index.js
Normal file
137
resources/formatter/index.js
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
"use strict";
|
||||||
|
const os = require('os');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const vscode = require('vscode');
|
||||||
|
const temp = require("temp");
|
||||||
|
|
||||||
|
const vlogFormatter = require("./vlogFormatter.js");
|
||||||
|
const vhdlFormatter = require("./vhdlFormatter.js");
|
||||||
|
|
||||||
|
class Formatter {
|
||||||
|
constructor() {
|
||||||
|
this.vlogFormatter = new VlogFormatter();
|
||||||
|
this.vhdlFormatter = new VhdlFormatter();
|
||||||
|
}
|
||||||
|
|
||||||
|
async provideDocumentFormattingEdits(document, options, token) {
|
||||||
|
const edits = [];
|
||||||
|
//Get document code
|
||||||
|
let code_document = document.getText();
|
||||||
|
let selection_document = this.getDocumentRange(document);
|
||||||
|
//Get selected text
|
||||||
|
let editor = vscode.window.activeTextEditor;
|
||||||
|
let selection_selected_text = '';
|
||||||
|
let code_selected_text = '';
|
||||||
|
if (editor !== undefined) {
|
||||||
|
selection_selected_text = editor.selection;
|
||||||
|
code_selected_text = editor.document.getText(editor.selection);
|
||||||
|
}
|
||||||
|
//Code to format
|
||||||
|
let code_to_format = '';
|
||||||
|
let selection_to_format = '';
|
||||||
|
if (code_selected_text !== '') {
|
||||||
|
code_to_format = code_selected_text;
|
||||||
|
selection_to_format = selection_selected_text;
|
||||||
|
} else {
|
||||||
|
code_to_format = code_document;
|
||||||
|
selection_to_format = selection_document;
|
||||||
|
}
|
||||||
|
|
||||||
|
let code_format = await this.format(document.languageId, code_to_format);
|
||||||
|
if (code_format === null) {
|
||||||
|
console.log("Error format code.");
|
||||||
|
return edits;
|
||||||
|
} else {
|
||||||
|
const replacement = vscode.TextEdit.replace(selection_to_format, code_format);
|
||||||
|
edits.push(replacement);
|
||||||
|
return edits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async format(language, code) {
|
||||||
|
let options = null;
|
||||||
|
let formatted_code = '';
|
||||||
|
try {
|
||||||
|
if (language === "vhdl") {
|
||||||
|
options = this.get_vhdl_config();
|
||||||
|
formatted_code = await this.vhdlFormatter.format_from_code(code, options);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
options = this.get_vlog_config();
|
||||||
|
formatted_code = await this.vlogFormatter.format_from_code(code, options);
|
||||||
|
}
|
||||||
|
return formatted_code;
|
||||||
|
} catch (error) {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get_vlog_config() {
|
||||||
|
let style = vscode.workspace.getConfiguration("function.lsp.formatter.vlog.default").get("style");
|
||||||
|
let args = vscode.workspace.getConfiguration("function.lsp.formatter.vlog.default").get("args");
|
||||||
|
return `--style=${style} ${args}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_vhdl_config() {
|
||||||
|
let configuration = vscode.workspace.getConfiguration('function.lsp.formatter.vhdl.default');
|
||||||
|
let settings = {
|
||||||
|
"RemoveComments": false,
|
||||||
|
"RemoveAsserts": false,
|
||||||
|
"CheckAlias": false,
|
||||||
|
"AlignComments": configuration.get('align-comments'),
|
||||||
|
"SignAlignSettings": {
|
||||||
|
"isRegional": true,
|
||||||
|
"isAll": true,
|
||||||
|
"mode": 'local',
|
||||||
|
"keyWords": [
|
||||||
|
"FUNCTION",
|
||||||
|
"IMPURE FUNCTION",
|
||||||
|
"GENERIC",
|
||||||
|
"PORT",
|
||||||
|
"PROCEDURE"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"KeywordCase": configuration.get('keyword-case'),
|
||||||
|
"TypeNameCase": configuration.get('type-name-case'),
|
||||||
|
"Indentation": ' '.repeat(configuration.get('indentation')),
|
||||||
|
"NewLineSettings": {
|
||||||
|
"newLineAfter": [
|
||||||
|
";",
|
||||||
|
"then"
|
||||||
|
],
|
||||||
|
"noNewLineAfter": []
|
||||||
|
},
|
||||||
|
"EndOfLine": "\n"
|
||||||
|
};
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDocumentRange(document) {
|
||||||
|
const lastLineId = document.lineCount - 1;
|
||||||
|
return new vscode.Range(0, 0, lastLineId, document.lineAt(lastLineId).text.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VlogFormatter {
|
||||||
|
async format_from_code(code, options) {
|
||||||
|
let verilogFormatter = await vlogFormatter();
|
||||||
|
verilogFormatter.FS.writeFile("/share/FILE_IN.v", code, { encoding: 'utf8' });
|
||||||
|
verilogFormatter.ccall('run', '', ['string'], [`${options} finish`]);
|
||||||
|
let formatted_code = verilogFormatter.FS.readFile("/share/FILE_OUT.v", { encoding: 'utf8' });
|
||||||
|
return formatted_code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VhdlFormatter {
|
||||||
|
async format_from_code(code, options) {
|
||||||
|
let beautifuler = new vhdlFormatter.Beautifuler();
|
||||||
|
let formatted_code = beautifuler.beauty(code, options);
|
||||||
|
return formatted_code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const hdlFormatterProvider = new Formatter();
|
||||||
|
module.exports = { hdlFormatterProvider };
|
910
resources/formatter/vhdlFormatter.js
Normal file
910
resources/formatter/vhdlFormatter.js
Normal file
@ -0,0 +1,910 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
class Beautifuler {
|
||||||
|
beauty(input, options) {
|
||||||
|
let new_line_after_symbols = new NewLineSettings();
|
||||||
|
new_line_after_symbols.newLineAfter = ["then", ";"];
|
||||||
|
new_line_after_symbols.noNewLineAfter = ["port", "generic"];
|
||||||
|
let settings = this.getDefaultBeautifierSettings(new_line_after_symbols);
|
||||||
|
settings.SignAlignSettings = new signAlignSettings(true, true, "local", ["PORT", "GENERIC"]);
|
||||||
|
|
||||||
|
const result = this.beautifyIntern(input, options);
|
||||||
|
if (result.err !== null) {
|
||||||
|
console.error(`-- [ERROR]: could not beautify`);
|
||||||
|
}
|
||||||
|
return result.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
beautifyIntern(input, settings) {
|
||||||
|
try {
|
||||||
|
const data = beautify(input, settings);
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
err: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
return {
|
||||||
|
data: null,
|
||||||
|
err,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefaultBeautifierSettings(newLineSettings, signAlignSettings = null, indentation = " ") {
|
||||||
|
return new BeautifierSettings(false, false, false, signAlignSettings, "lowercase", "lowercase", indentation, newLineSettings, "\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.Beautifuler = Beautifuler;
|
||||||
|
|
||||||
|
// VHDLFormatter
|
||||||
|
const ILEscape = "@@";
|
||||||
|
const ILCommentPrefix = ILEscape + "comments";
|
||||||
|
const ILIndentedReturnPrefix = ILEscape;
|
||||||
|
const ILQuote = "⨵";
|
||||||
|
const ILSingleQuote = "⦼";
|
||||||
|
const ILBackslash = "⨸";
|
||||||
|
const ILSemicolon = "⨴";
|
||||||
|
var FormatMode;
|
||||||
|
(function (FormatMode) {
|
||||||
|
FormatMode[FormatMode["Default"] = 0] = "Default";
|
||||||
|
FormatMode[FormatMode["EndsWithSemicolon"] = 1] = "EndsWithSemicolon";
|
||||||
|
FormatMode[FormatMode["CaseWhen"] = 2] = "CaseWhen";
|
||||||
|
FormatMode[FormatMode["IfElse"] = 3] = "IfElse";
|
||||||
|
FormatMode[FormatMode["PortGeneric"] = 4] = "PortGeneric";
|
||||||
|
})(FormatMode || (FormatMode = {}));
|
||||||
|
let Mode = FormatMode.Default;
|
||||||
|
exports.RemoveAsserts = exports.ApplyNoNewLineAfter = exports.beautify3 = exports.beautifySemicolonBlock = exports.beautifyPackageIsNewBlock = exports.beautifyComponentBlock = exports.beautifyCaseBlock = exports.AlignSign = exports.AlignSigns = exports.beautifyPortGenericBlock = exports.FormattedLineToString = exports.FormattedLine = exports.beautify = exports.BeautifierSettings = exports.signAlignSettings = exports.SetNewLinesAfterSymbols = exports.NewLineSettings = void 0;
|
||||||
|
class NewLineSettings {
|
||||||
|
constructor() {
|
||||||
|
this.newLineAfter = [];
|
||||||
|
this.noNewLineAfter = [];
|
||||||
|
}
|
||||||
|
newLineAfterPush(keyword) {
|
||||||
|
this.newLineAfter.push(keyword);
|
||||||
|
}
|
||||||
|
noNewLineAfterPush(keyword) {
|
||||||
|
this.noNewLineAfter.push(keyword);
|
||||||
|
}
|
||||||
|
push(keyword, addNewLine) {
|
||||||
|
let str = addNewLine.toLowerCase();
|
||||||
|
if (str == "none") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (!str.startsWith("no")) {
|
||||||
|
this.newLineAfterPush(keyword);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.noNewLineAfterPush(keyword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.NewLineSettings = NewLineSettings;
|
||||||
|
function ConstructNewLineSettings(dict) {
|
||||||
|
let settings = new NewLineSettings();
|
||||||
|
for (let key in dict) {
|
||||||
|
settings.push(key, dict[key]);
|
||||||
|
}
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
String.prototype.regexCount = function (pattern) {
|
||||||
|
if (pattern.flags.indexOf("g") < 0) {
|
||||||
|
pattern = new RegExp(pattern.source, pattern.flags + "g");
|
||||||
|
}
|
||||||
|
return (this.match(pattern) || []).length;
|
||||||
|
};
|
||||||
|
String.prototype.count = function (text) {
|
||||||
|
return this.split(text).length - 1;
|
||||||
|
};
|
||||||
|
String.prototype.regexStartsWith = function (pattern) {
|
||||||
|
var searchResult = this.search(pattern);
|
||||||
|
return searchResult == 0;
|
||||||
|
};
|
||||||
|
String.prototype.regexIndexOf = function (pattern, startIndex) {
|
||||||
|
startIndex = startIndex || 0;
|
||||||
|
var searchResult = this.substr(startIndex).search(pattern);
|
||||||
|
return (-1 === searchResult) ? -1 : searchResult + startIndex;
|
||||||
|
};
|
||||||
|
String.prototype.regexLastIndexOf = function (pattern, startIndex) {
|
||||||
|
pattern = (pattern.global) ? pattern :
|
||||||
|
new RegExp(pattern.source, 'g' + (pattern.ignoreCase ? 'i' : '') + (pattern.multiline ? 'm' : ''));
|
||||||
|
if (typeof (startIndex) === 'undefined') {
|
||||||
|
startIndex = this.length;
|
||||||
|
}
|
||||||
|
else if (startIndex < 0) {
|
||||||
|
startIndex = 0;
|
||||||
|
}
|
||||||
|
const stringToWorkWith = this.substring(0, startIndex + 1);
|
||||||
|
let lastIndexOf = -1;
|
||||||
|
let nextStop = 0;
|
||||||
|
let result;
|
||||||
|
while ((result = pattern.exec(stringToWorkWith)) != null) {
|
||||||
|
lastIndexOf = result.index;
|
||||||
|
pattern.lastIndex = ++nextStop;
|
||||||
|
}
|
||||||
|
return lastIndexOf;
|
||||||
|
};
|
||||||
|
String.prototype.reverse = function () {
|
||||||
|
return this.split('').reverse().join('');
|
||||||
|
};
|
||||||
|
String.prototype.convertToRegexBlockWords = function () {
|
||||||
|
let result = new RegExp("(" + this + ")([^\\w]|$)");
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Array.prototype.convertToRegexBlockWords = function () {
|
||||||
|
let wordsStr = this.join("|");
|
||||||
|
let result = new RegExp("(" + wordsStr + ")([^\\w]|$)");
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
function EscapeComments(arr) {
|
||||||
|
var comments = [];
|
||||||
|
var count = 0;
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
var line = arr[i];
|
||||||
|
var commentStartIndex = line.indexOf("--");
|
||||||
|
if (commentStartIndex >= 0) {
|
||||||
|
comments.push(line.substr(commentStartIndex));
|
||||||
|
arr[i] = line.substr(0, commentStartIndex) + ILCommentPrefix + count;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var isInComment = false;
|
||||||
|
var commentRegex = new RegExp("(?<=" + ILCommentPrefix + "[\\d]+).");
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
var commentStartIndex = 0;
|
||||||
|
var hasComment = true;
|
||||||
|
var commentEndInlineIndex = 0;
|
||||||
|
while (hasComment) {
|
||||||
|
var line = arr[i];
|
||||||
|
if (!isInComment) {
|
||||||
|
commentStartIndex = line.indexOf("/*");
|
||||||
|
var commentEndIndex = line.indexOf("*/", commentStartIndex);
|
||||||
|
if (commentStartIndex >= 0) {
|
||||||
|
if (commentEndIndex >= 0) {
|
||||||
|
commentEndInlineIndex = commentEndIndex + 2;
|
||||||
|
isInComment = false;
|
||||||
|
comments.push(line.substring(commentStartIndex, commentEndInlineIndex));
|
||||||
|
arr[i] = line.substr(0, commentStartIndex) + ILCommentPrefix + count + line.substr(commentEndInlineIndex);
|
||||||
|
count++;
|
||||||
|
hasComment = true;
|
||||||
|
if (commentStartIndex + 2 == line.length) {
|
||||||
|
hasComment = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
isInComment = true;
|
||||||
|
comments.push(line.substr(commentStartIndex));
|
||||||
|
arr[i] = line.substr(0, commentStartIndex) + ILCommentPrefix + count;
|
||||||
|
count++;
|
||||||
|
hasComment = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hasComment = false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isInComment) {
|
||||||
|
var lastCommentEndIndex = line.regexLastIndexOf(commentRegex, line.length);
|
||||||
|
if (commentStartIndex == 0) {
|
||||||
|
var commentEndIndex = line.indexOf("*/", lastCommentEndIndex);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var commentEndIndex = line.indexOf("*/", commentStartIndex);
|
||||||
|
}
|
||||||
|
if (commentEndIndex >= 0) {
|
||||||
|
isInComment = false;
|
||||||
|
comments.push(line.substr(0, commentEndIndex + 2));
|
||||||
|
arr[i] = ILCommentPrefix + count + line.substr(commentEndIndex + 2);
|
||||||
|
count++;
|
||||||
|
hasComment = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
comments.push(line);
|
||||||
|
arr[i] = ILCommentPrefix + count;
|
||||||
|
count++;
|
||||||
|
hasComment = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return comments;
|
||||||
|
}
|
||||||
|
function ToLowerCases(arr) {
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
arr[i] = arr[i].toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function ToUpperCases(arr) {
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
arr[i] = arr[i].toUpperCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function ToCamelCases(arr) {
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
arr[i] = arr[i].charAt(0) + arr[i].slice(1).toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function ReplaceKeyWords(text, keywords) {
|
||||||
|
for (var k = 0; k < keywords.length; k++) {
|
||||||
|
text = text.replace(new RegExp("([^a-zA-Z0-9_@]|^)" + keywords[k] + "([^a-zA-Z0-9_]|$)", 'gi'), "$1" + keywords[k] + "$2");
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
function SetKeywordCase(input, keywordcase, keywords) {
|
||||||
|
let inputcase = keywordcase.toLowerCase();
|
||||||
|
switch (inputcase) {
|
||||||
|
case "lowercase":
|
||||||
|
ToLowerCases(keywords);
|
||||||
|
break;
|
||||||
|
case "defaultcase":
|
||||||
|
ToCamelCases(keywords);
|
||||||
|
break;
|
||||||
|
case "uppercase":
|
||||||
|
ToUpperCases(keywords);
|
||||||
|
}
|
||||||
|
input = ReplaceKeyWords(input, keywords);
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
function SetNewLinesAfterSymbols(text, newLineSettings) {
|
||||||
|
if (newLineSettings == null) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
if (newLineSettings.newLineAfter != null) {
|
||||||
|
newLineSettings.newLineAfter.forEach(symbol => {
|
||||||
|
let upper = symbol.toUpperCase();
|
||||||
|
var rexString = "(" + upper + ")[ ]?([^ \r\n@])";
|
||||||
|
let regex = null;
|
||||||
|
if (upper.regexStartsWith(/\w/)) {
|
||||||
|
regex = new RegExp("\\b" + rexString, "g");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
regex = new RegExp(rexString, "g");
|
||||||
|
}
|
||||||
|
text = text.replace(regex, '$1\r\n$2');
|
||||||
|
if (upper == "PORT") {
|
||||||
|
text = text.replace(/\bPORT\b\s+MAP/, "PORT MAP");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (newLineSettings.noNewLineAfter != null) {
|
||||||
|
newLineSettings.noNewLineAfter.forEach(symbol => {
|
||||||
|
let rexString = "(" + symbol.toUpperCase() + ")[ \r\n]+([^@])";
|
||||||
|
let regex = null;
|
||||||
|
if (symbol.regexStartsWith(/\w/)) {
|
||||||
|
regex = new RegExp("\\b" + rexString, "g");
|
||||||
|
text = text.replace(regex, '$1 $2');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
regex = new RegExp(rexString, "g");
|
||||||
|
}
|
||||||
|
text = text.replace(regex, '$1 $2');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
exports.SetNewLinesAfterSymbols = SetNewLinesAfterSymbols;
|
||||||
|
class signAlignSettings {
|
||||||
|
constructor(isRegional, isAll, mode, keyWords) {
|
||||||
|
this.isRegional = isRegional;
|
||||||
|
this.isAll = isAll;
|
||||||
|
this.mode = mode;
|
||||||
|
this.keyWords = keyWords;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.signAlignSettings = signAlignSettings;
|
||||||
|
class BeautifierSettings {
|
||||||
|
constructor(removeComments, removeReport, checkAlias, alignComments, signAlignSettings, keywordCase, typeNameCase, indentation, newLineSettings, endOfLine, addNewLine) {
|
||||||
|
this.RemoveComments = removeComments;
|
||||||
|
this.RemoveAsserts = removeReport;
|
||||||
|
this.CheckAlias = checkAlias;
|
||||||
|
this.AlignComments = alignComments;
|
||||||
|
this.SignAlignSettings = signAlignSettings;
|
||||||
|
this.KeywordCase = keywordCase;
|
||||||
|
this.TypeNameCase = typeNameCase;
|
||||||
|
this.Indentation = indentation;
|
||||||
|
this.NewLineSettings = newLineSettings;
|
||||||
|
this.EndOfLine = endOfLine;
|
||||||
|
this.AddNewLine = addNewLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.BeautifierSettings = BeautifierSettings;
|
||||||
|
let KeyWords = ["ABS", "ACCESS", "AFTER", "ALIAS", "ALL", "AND", "ARCHITECTURE", "ARRAY", "ASSERT", "ATTRIBUTE", "BEGIN", "BLOCK", "BODY", "BUFFER", "BUS", "CASE", "COMPONENT", "CONFIGURATION", "CONSTANT", "CONTEXT", "COVER", "DISCONNECT", "DOWNTO", "DEFAULT", "ELSE", "ELSIF", "END", "ENTITY", "EXIT", "FAIRNESS", "FILE", "FOR", "FORCE", "FUNCTION", "GENERATE", "GENERIC", "GROUP", "GUARDED", "IF", "IMPURE", "IN", "INERTIAL", "INOUT", "IS", "LABEL", "LIBRARY", "LINKAGE", "LITERAL", "LOOP", "MAP", "MOD", "NAND", "NEW", "NEXT", "NOR", "NOT", "NULL", "OF", "ON", "OPEN", "OR", "OTHERS", "OUT", "PACKAGE", "PORT", "POSTPONED", "PROCEDURE", "PROCESS", "PROPERTY", "PROTECTED", "PURE", "RANGE", "RECORD", "REGISTER", "REJECT", "RELEASE", "REM", "REPORT", "RESTRICT", "RESTRICT_GUARANTEE", "RETURN", "ROL", "ROR", "SELECT", "SEQUENCE", "SEVERITY", "SHARED", "SIGNAL", "SLA", "SLL", "SRA", "SRL", "STRONG", "SUBTYPE", "THEN", "TO", "TRANSPORT", "TYPE", "UNAFFECTED", "UNITS", "UNTIL", "USE", "VARIABLE", "VMODE", "VPROP", "VUNIT", "WAIT", "WHEN", "WHILE", "WITH", "XNOR", "XOR"];
|
||||||
|
let TypeNames = ["BOOLEAN", "BIT", "CHARACTER", "INTEGER", "TIME", "NATURAL", "POSITIVE", "STD_LOGIC", "STD_LOGIC_VECTOR", "STD_ULOGIC", "STD_ULOGIC_VECTOR", "STRING"];
|
||||||
|
function beautify(input, settings) {
|
||||||
|
input = input.replace(/\r\n/g, "\n");
|
||||||
|
input = input.replace(/\n/g, "\r\n");
|
||||||
|
var arr = input.split("\r\n");
|
||||||
|
var comments = EscapeComments(arr);
|
||||||
|
var backslashes = escapeText(arr, "\\\\[^\\\\]+\\\\", ILBackslash);
|
||||||
|
let quotes = escapeText(arr, '"([^"]+)"', ILQuote);
|
||||||
|
let singleQuotes = escapeText(arr, "'[^']'", ILSingleQuote);
|
||||||
|
RemoveLeadingWhitespaces(arr);
|
||||||
|
input = arr.join("\r\n");
|
||||||
|
if (settings.RemoveComments) {
|
||||||
|
input = input.replace(/\r\n[ \t]*@@comments[0-9]+[ \t]*\r\n/g, '\r\n');
|
||||||
|
input = input.replace(/@@comments[0-9]+/g, '');
|
||||||
|
comments = [];
|
||||||
|
}
|
||||||
|
input = SetKeywordCase(input, "uppercase", KeyWords);
|
||||||
|
input = SetKeywordCase(input, "uppercase", TypeNames);
|
||||||
|
input = RemoveExtraNewLines(input);
|
||||||
|
input = input.replace(/[\t ]+/g, ' ');
|
||||||
|
input = input.replace(/\([\t ]+/g, '\(');
|
||||||
|
input = input.replace(/[ ]+;/g, ';');
|
||||||
|
input = input.replace(/:[ ]*(PROCESS|ENTITY)/gi, ':$1');
|
||||||
|
arr = input.split("\r\n");
|
||||||
|
if (settings.RemoveAsserts) {
|
||||||
|
RemoveAsserts(arr); //RemoveAsserts must be after EscapeQuotes
|
||||||
|
}
|
||||||
|
ReserveSemicolonInKeywords(arr);
|
||||||
|
input = arr.join("\r\n");
|
||||||
|
input = input.replace(/\b(PORT|GENERIC)\b\s+MAP/g, '$1 MAP');
|
||||||
|
input = input.replace(/\b(PORT|PROCESS|GENERIC)\b[\s]*\(/g, '$1 (');
|
||||||
|
let newLineSettings = settings.NewLineSettings;
|
||||||
|
if (newLineSettings != null) {
|
||||||
|
input = SetNewLinesAfterSymbols(input, newLineSettings);
|
||||||
|
arr = input.split("\r\n");
|
||||||
|
ApplyNoNewLineAfter(arr, newLineSettings.noNewLineAfter);
|
||||||
|
input = arr.join("\r\n");
|
||||||
|
}
|
||||||
|
input = input.replace(/([a-zA-Z0-9\); ])\);(@@comments[0-9]+)?@@end/g, '$1\r\n);$2@@end');
|
||||||
|
input = input.replace(/[ ]?([&=:\-\+|\*]|[<>]+)[ ]?/g, ' $1 ');
|
||||||
|
input = input.replace(/(\d+e) +([+\-]) +(\d+)/g, '$1$2$3'); // fix exponential notation format broken by previous step
|
||||||
|
input = input.replace(/[ ]?([,])[ ]?/g, '$1 ');
|
||||||
|
input = input.replace(/[ ]?(['"])(THEN)/g, '$1 $2');
|
||||||
|
input = input.replace(/[ ]?(\?)?[ ]?(<|:|>|\/)?[ ]+(=)?[ ]?/g, ' $1$2$3 ');
|
||||||
|
input = input.replace(/(IF)[ ]?([\(\)])/g, '$1 $2');
|
||||||
|
input = input.replace(/([\(\)])[ ]?(THEN)/gi, '$1 $2');
|
||||||
|
input = input.replace(/(^|[\(\)])[ ]?(AND|OR|XOR|XNOR)[ ]*([\(])/g, '$1 $2 $3');
|
||||||
|
input = input.replace(/ ([\-\*\/=+<>])[ ]*([\-\*\/=+<>]) /g, " $1$2 ");
|
||||||
|
//input = input.replace(/\r\n[ \t]+--\r\n/g, "\r\n");
|
||||||
|
input = input.replace(/[ ]+/g, ' ');
|
||||||
|
input = input.replace(/[ \t]+\r\n/g, "\r\n");
|
||||||
|
input = input.replace(/\r\n\r\n\r\n/g, '\r\n');
|
||||||
|
input = input.replace(/[\r\n\s]+$/g, '');
|
||||||
|
input = input.replace(/[ \t]+\)/g, ')');
|
||||||
|
input = input.replace(/\s*\)\s+RETURN\s+([\w]+;)/g, '\r\n) RETURN $1'); //function(..)\r\nreturn type; -> function(..\r\n)return type;
|
||||||
|
input = input.replace(/\)\s*(@@\w+)\r\n\s*RETURN\s+([\w]+;)/g, ') $1\r\n' + ILIndentedReturnPrefix + 'RETURN $2'); //function(..)\r\nreturn type; -> function(..\r\n)return type;
|
||||||
|
let keywordAndSignRegex = new RegExp("(\\b" + KeyWords.join("\\b|\\b") + "\\b) +([\\-+]) +(\\w)", "g");
|
||||||
|
input = input.replace(keywordAndSignRegex, "$1 $2$3"); // `WHEN - 2` -> `WHEN -2`
|
||||||
|
input = input.replace(/([,|]) +([+\-]) +(\w)/g, '$1 $2$3'); // `1, - 2)` -> `1, -2)`
|
||||||
|
input = input.replace(/(\() +([+\-]) +(\w)/g, '$1$2$3'); // `( - 2)` -> `(-2)`
|
||||||
|
arr = input.split("\r\n");
|
||||||
|
let result = [];
|
||||||
|
beautify3(arr, result, settings, 0, 0);
|
||||||
|
var alignSettings = settings.SignAlignSettings;
|
||||||
|
if (alignSettings != null && alignSettings.isAll) {
|
||||||
|
AlignSigns(result, 0, result.length - 1, alignSettings.mode, settings.AlignComments);
|
||||||
|
}
|
||||||
|
arr = FormattedLineToString(result, settings.Indentation);
|
||||||
|
input = arr.join("\r\n");
|
||||||
|
input = input.replace(/@@RETURN/g, "RETURN");
|
||||||
|
input = SetKeywordCase(input, settings.KeywordCase, KeyWords);
|
||||||
|
input = SetKeywordCase(input, settings.TypeNameCase, TypeNames);
|
||||||
|
input = replaceEscapedWords(input, quotes, ILQuote);
|
||||||
|
input = replaceEscapedWords(input, singleQuotes, ILSingleQuote);
|
||||||
|
input = replaceEscapedComments(input, comments, ILCommentPrefix);
|
||||||
|
input = replaceEscapedWords(input, backslashes, ILBackslash);
|
||||||
|
input = input.replace(new RegExp(ILSemicolon, "g"), ";");
|
||||||
|
input = input.replace(/@@[a-z]+/g, "");
|
||||||
|
var escapedTexts = new RegExp("[" + ILBackslash + ILQuote + ILSingleQuote + "]", "g");
|
||||||
|
input = input.replace(escapedTexts, "");
|
||||||
|
input = input.replace(/\r\n/g, settings.EndOfLine);
|
||||||
|
if (settings.AddNewLine && !input.endsWith(settings.EndOfLine)) {
|
||||||
|
input += settings.EndOfLine;
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
exports.beautify = beautify;
|
||||||
|
function replaceEscapedWords(input, arr, prefix) {
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
var text = arr[i];
|
||||||
|
var regex = new RegExp("(" + prefix + "){" + text.length + "}");
|
||||||
|
input = input.replace(regex, text);
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
function replaceEscapedComments(input, arr, prefix) {
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
input = input.replace(prefix + i, arr[i]);
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
function RemoveLeadingWhitespaces(arr) {
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
arr[i] = arr[i].replace(/^\s+/, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class FormattedLine {
|
||||||
|
constructor(line, indent) {
|
||||||
|
this.Line = line;
|
||||||
|
this.Indent = indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.FormattedLine = FormattedLine;
|
||||||
|
function FormattedLineToString(arr, indentation) {
|
||||||
|
let result = [];
|
||||||
|
if (arr == null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (indentation == null) {
|
||||||
|
indentation = "";
|
||||||
|
}
|
||||||
|
arr.forEach(i => {
|
||||||
|
if (i instanceof FormattedLine) {
|
||||||
|
if (i.Line.length > 0) {
|
||||||
|
result.push((Array(i.Indent + 1).join(indentation)) + i.Line);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result.push("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = result.concat(FormattedLineToString(i, indentation));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
exports.FormattedLineToString = FormattedLineToString;
|
||||||
|
function GetCloseparentheseEndIndex(inputs, startIndex) {
|
||||||
|
let openParentheseCount = 0;
|
||||||
|
let closeParentheseCount = 0;
|
||||||
|
for (let i = startIndex; i < inputs.length; i++) {
|
||||||
|
let input = inputs[i];
|
||||||
|
openParentheseCount += input.count("(");
|
||||||
|
closeParentheseCount += input.count(")");
|
||||||
|
if (openParentheseCount > 0
|
||||||
|
&& openParentheseCount <= closeParentheseCount) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return startIndex;
|
||||||
|
}
|
||||||
|
function beautifyPortGenericBlock(inputs, result, settings, startIndex, parentEndIndex, indent, mode) {
|
||||||
|
let firstLine = inputs[startIndex];
|
||||||
|
let regex = new RegExp("[\\w\\s:]*(" + mode + ")([\\s]|$)");
|
||||||
|
if (!firstLine.regexStartsWith(regex)) {
|
||||||
|
return [startIndex, parentEndIndex];
|
||||||
|
}
|
||||||
|
let firstLineHasParenthese = firstLine.indexOf("(") >= 0;
|
||||||
|
let hasParenthese = firstLineHasParenthese;
|
||||||
|
let blockBodyStartIndex = startIndex;
|
||||||
|
let secondLineHasParenthese = startIndex + 1 < inputs.length && inputs[startIndex + 1].startsWith("(");
|
||||||
|
if (secondLineHasParenthese) {
|
||||||
|
hasParenthese = true;
|
||||||
|
blockBodyStartIndex++;
|
||||||
|
}
|
||||||
|
let endIndex = hasParenthese ? GetCloseparentheseEndIndex(inputs, startIndex) : startIndex;
|
||||||
|
if (endIndex != startIndex && firstLineHasParenthese) {
|
||||||
|
inputs[startIndex] = inputs[startIndex].replace(/\b(PORT|GENERIC|PROCEDURE)\b([\w ]+)\(([\w\(\) ]+)/, '$1$2(\r\n$3');
|
||||||
|
let newInputs = inputs[startIndex].split("\r\n");
|
||||||
|
if (newInputs.length == 2) {
|
||||||
|
inputs[startIndex] = newInputs[0];
|
||||||
|
inputs.splice(startIndex + 1, 0, newInputs[1]);
|
||||||
|
endIndex++;
|
||||||
|
parentEndIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (endIndex > startIndex + 1 && secondLineHasParenthese) {
|
||||||
|
inputs[startIndex + 1] = inputs[startIndex + 1].replace(/\(([\w\(\) ]+)/, '(\r\n$1');
|
||||||
|
let newInputs = inputs[startIndex + 1].split("\r\n");
|
||||||
|
if (newInputs.length == 2) {
|
||||||
|
inputs[startIndex + 1] = newInputs[0];
|
||||||
|
inputs.splice(startIndex + 2, 0, newInputs[1]);
|
||||||
|
endIndex++;
|
||||||
|
parentEndIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (firstLineHasParenthese && inputs[startIndex].indexOf("MAP") > 0) {
|
||||||
|
inputs[startIndex] = inputs[startIndex].replace(/([^\w])(MAP)\s+\(/g, '$1$2(');
|
||||||
|
}
|
||||||
|
result.push(new FormattedLine(inputs[startIndex], indent));
|
||||||
|
if (secondLineHasParenthese) {
|
||||||
|
let secondLineIndent = indent;
|
||||||
|
if (endIndex == startIndex + 1) {
|
||||||
|
secondLineIndent++;
|
||||||
|
}
|
||||||
|
result.push(new FormattedLine(inputs[startIndex + 1], secondLineIndent));
|
||||||
|
}
|
||||||
|
let blockBodyEndIndex = endIndex;
|
||||||
|
let i = beautify3(inputs, result, settings, blockBodyStartIndex + 1, indent + 1, endIndex);
|
||||||
|
if (inputs[i].startsWith(")")) {
|
||||||
|
result[i].Indent--;
|
||||||
|
blockBodyEndIndex--;
|
||||||
|
}
|
||||||
|
var alignSettings = settings.SignAlignSettings;
|
||||||
|
if (alignSettings != null) {
|
||||||
|
if (alignSettings.isRegional && !alignSettings.isAll
|
||||||
|
&& alignSettings.keyWords != null
|
||||||
|
&& alignSettings.keyWords.indexOf(mode) >= 0) {
|
||||||
|
blockBodyStartIndex++;
|
||||||
|
AlignSigns(result, blockBodyStartIndex, blockBodyEndIndex, alignSettings.mode, settings.AlignComments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [i, parentEndIndex];
|
||||||
|
}
|
||||||
|
exports.beautifyPortGenericBlock = beautifyPortGenericBlock;
|
||||||
|
function AlignSigns(result, startIndex, endIndex, mode, alignComments) {
|
||||||
|
AlignSign_(result, startIndex, endIndex, ":", mode);
|
||||||
|
AlignSign_(result, startIndex, endIndex, ":=", mode);
|
||||||
|
AlignSign_(result, startIndex, endIndex, "<=", mode);
|
||||||
|
AlignSign_(result, startIndex, endIndex, "=>", mode);
|
||||||
|
if (alignComments) {
|
||||||
|
AlignSign_(result, startIndex, endIndex, "@@comments", mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.AlignSigns = AlignSigns;
|
||||||
|
function AlignSign_(result, startIndex, endIndex, symbol, mode) {
|
||||||
|
let maxSymbolIndex = -1;
|
||||||
|
let symbolIndices = {};
|
||||||
|
let startLine = startIndex;
|
||||||
|
let labelAndKeywords = [
|
||||||
|
"([\\w\\s]*:(\\s)*PROCESS)",
|
||||||
|
"([\\w\\s]*:(\\s)*POSTPONED PROCESS)",
|
||||||
|
"([\\w\\s]*:\\s*$)",
|
||||||
|
"([\\w\\s]*:.*\\s+GENERATE)"
|
||||||
|
];
|
||||||
|
let labelAndKeywordsStr = labelAndKeywords.join("|");
|
||||||
|
let labelAndKeywordsRegex = new RegExp("(" + labelAndKeywordsStr + ")([^\\w]|$)");
|
||||||
|
for (let i = startIndex; i <= endIndex; i++) {
|
||||||
|
let line = result[i].Line;
|
||||||
|
if (symbol == ":" && line.regexStartsWith(labelAndKeywordsRegex)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let regex = new RegExp("([\\s\\w\\\\]|^)" + symbol + "([\\s\\w\\\\]|$)");
|
||||||
|
if (line.regexCount(regex) > 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let colonIndex = line.regexIndexOf(regex);
|
||||||
|
if (colonIndex > 0) {
|
||||||
|
maxSymbolIndex = Math.max(maxSymbolIndex, colonIndex);
|
||||||
|
symbolIndices[i] = colonIndex;
|
||||||
|
}
|
||||||
|
else if ((mode != "local" && !line.startsWith(ILCommentPrefix) && line.length != 0)
|
||||||
|
|| (mode == "local")) {
|
||||||
|
if (startLine < i - 1) // if cannot find the symbol, a block of symbols ends
|
||||||
|
{
|
||||||
|
AlignSign(result, startLine, i - 1, symbol, maxSymbolIndex, symbolIndices);
|
||||||
|
}
|
||||||
|
maxSymbolIndex = -1;
|
||||||
|
symbolIndices = {};
|
||||||
|
startLine = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (startLine < endIndex) // if cannot find the symbol, a block of symbols ends
|
||||||
|
{
|
||||||
|
AlignSign(result, startLine, endIndex, symbol, maxSymbolIndex, symbolIndices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function AlignSign(result, startIndex, endIndex, symbol, maxSymbolIndex = -1, symbolIndices = {}) {
|
||||||
|
if (maxSymbolIndex < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let lineIndex in symbolIndices) {
|
||||||
|
let symbolIndex = symbolIndices[lineIndex];
|
||||||
|
if (symbolIndex == maxSymbolIndex) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let line = result[lineIndex].Line;
|
||||||
|
result[lineIndex].Line = line.substring(0, symbolIndex)
|
||||||
|
+ (Array(maxSymbolIndex - symbolIndex + 1).join(" "))
|
||||||
|
+ line.substring(symbolIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.AlignSign = AlignSign;
|
||||||
|
function beautifyCaseBlock(inputs, result, settings, startIndex, indent) {
|
||||||
|
if (!inputs[startIndex].regexStartsWith(/(.+:\s*)?(CASE)([\s]|$)/)) {
|
||||||
|
return startIndex;
|
||||||
|
}
|
||||||
|
result.push(new FormattedLine(inputs[startIndex], indent));
|
||||||
|
let i = beautify3(inputs, result, settings, startIndex + 1, indent + 2);
|
||||||
|
result[i].Indent = indent;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
exports.beautifyCaseBlock = beautifyCaseBlock;
|
||||||
|
function getSemicolonBlockEndIndex(inputs, settings, startIndex, parentEndIndex) {
|
||||||
|
let endIndex = 0;
|
||||||
|
let openBracketsCount = 0;
|
||||||
|
let closeBracketsCount = 0;
|
||||||
|
for (let i = startIndex; i < inputs.length; i++) {
|
||||||
|
let input = inputs[i];
|
||||||
|
let indexOfSemicolon = input.indexOf(";");
|
||||||
|
let splitIndex = indexOfSemicolon < 0 ? input.length : indexOfSemicolon + 1;
|
||||||
|
let stringBeforeSemicolon = input.substring(0, splitIndex);
|
||||||
|
let stringAfterSemicolon = input.substring(splitIndex);
|
||||||
|
stringAfterSemicolon = stringAfterSemicolon.replace(new RegExp(ILCommentPrefix + "[0-9]+"), "");
|
||||||
|
openBracketsCount += stringBeforeSemicolon.count("(");
|
||||||
|
closeBracketsCount += stringBeforeSemicolon.count(")");
|
||||||
|
if (indexOfSemicolon < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (openBracketsCount == closeBracketsCount) {
|
||||||
|
endIndex = i;
|
||||||
|
if (stringAfterSemicolon.trim().length > 0 && settings.NewLineSettings.newLineAfter.indexOf(";") >= 0) {
|
||||||
|
inputs[i] = stringBeforeSemicolon;
|
||||||
|
inputs.splice(i, 0, stringAfterSemicolon);
|
||||||
|
parentEndIndex++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [endIndex, parentEndIndex];
|
||||||
|
}
|
||||||
|
function beautifyComponentBlock(inputs, result, settings, startIndex, parentEndIndex, indent) {
|
||||||
|
let endIndex = startIndex;
|
||||||
|
for (let i = startIndex; i < inputs.length; i++) {
|
||||||
|
if (inputs[i].regexStartsWith(/END(\s|$)/)) {
|
||||||
|
endIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(new FormattedLine(inputs[startIndex], indent));
|
||||||
|
if (endIndex != startIndex) {
|
||||||
|
let actualEndIndex = beautify3(inputs, result, settings, startIndex + 1, indent + 1, endIndex);
|
||||||
|
let incremental = actualEndIndex - endIndex;
|
||||||
|
endIndex += incremental;
|
||||||
|
parentEndIndex += incremental;
|
||||||
|
}
|
||||||
|
return [endIndex, parentEndIndex];
|
||||||
|
}
|
||||||
|
exports.beautifyComponentBlock = beautifyComponentBlock;
|
||||||
|
function beautifyPackageIsNewBlock(inputs, result, settings, startIndex, parentEndIndex, indent) {
|
||||||
|
let endIndex = startIndex;
|
||||||
|
for (let i = startIndex; i < inputs.length; i++) {
|
||||||
|
if (inputs[i].regexIndexOf(/;(\s|$)/) >= 0) {
|
||||||
|
endIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(new FormattedLine(inputs[startIndex], indent));
|
||||||
|
if (endIndex != startIndex) {
|
||||||
|
let actualEndIndex = beautify3(inputs, result, settings, startIndex + 1, indent + 1, endIndex);
|
||||||
|
let incremental = actualEndIndex - endIndex;
|
||||||
|
endIndex += incremental;
|
||||||
|
parentEndIndex += incremental;
|
||||||
|
}
|
||||||
|
return [endIndex, parentEndIndex];
|
||||||
|
}
|
||||||
|
exports.beautifyPackageIsNewBlock = beautifyPackageIsNewBlock;
|
||||||
|
function beautifySemicolonBlock(inputs, result, settings, startIndex, parentEndIndex, indent) {
|
||||||
|
let endIndex = startIndex;
|
||||||
|
[endIndex, parentEndIndex] = getSemicolonBlockEndIndex(inputs, settings, startIndex, parentEndIndex);
|
||||||
|
result.push(new FormattedLine(inputs[startIndex], indent));
|
||||||
|
if (endIndex != startIndex) {
|
||||||
|
let i = beautify3(inputs, result, settings, startIndex + 1, indent + 1, endIndex);
|
||||||
|
}
|
||||||
|
return [endIndex, parentEndIndex];
|
||||||
|
}
|
||||||
|
exports.beautifySemicolonBlock = beautifySemicolonBlock;
|
||||||
|
function beautify3(inputs, result, settings, startIndex, indent, endIndex) {
|
||||||
|
let i;
|
||||||
|
let regexOneLineBlockKeyWords = new RegExp(/(PROCEDURE)[^\w](?!.+[^\w]IS([^\w]|$))/); //match PROCEDURE..; but not PROCEDURE .. IS;
|
||||||
|
let regexFunctionMultiLineBlockKeyWords = new RegExp(/(FUNCTION|IMPURE FUNCTION)[^\w](?=.+[^\w]IS([^\w]|$))/); //match FUNCTION .. IS; but not FUNCTION
|
||||||
|
let blockMidKeyWords = ["BEGIN"];
|
||||||
|
let blockStartsKeyWords = [
|
||||||
|
"IF",
|
||||||
|
"CASE",
|
||||||
|
"ARCHITECTURE",
|
||||||
|
"PROCEDURE",
|
||||||
|
"PACKAGE",
|
||||||
|
"(([\\w\\s]*:)?(\\s)*PROCESS)",
|
||||||
|
"(([\\w\\s]*:)?(\\s)*POSTPONED PROCESS)",
|
||||||
|
"(.*\\s*PROTECTED)",
|
||||||
|
"(COMPONENT)",
|
||||||
|
"(ENTITY(?!.+;))",
|
||||||
|
"FOR",
|
||||||
|
"WHILE",
|
||||||
|
"LOOP",
|
||||||
|
"(.*\\s*GENERATE)",
|
||||||
|
"(CONTEXT[\\w\\s\\\\]+IS)",
|
||||||
|
"(CONFIGURATION(?!.+;))",
|
||||||
|
"BLOCK",
|
||||||
|
"UNITS",
|
||||||
|
"\\w+\\s+\\w+\\s+IS\\s+RECORD"
|
||||||
|
];
|
||||||
|
let blockEndsKeyWords = ["END", ".*\\)\\s*RETURN\\s+[\\w]+;"];
|
||||||
|
let indentedEndsKeyWords = [ILIndentedReturnPrefix + "RETURN\\s+\\w+;"];
|
||||||
|
let blockEndsWithSemicolon = [
|
||||||
|
"(WITH\\s+[\\w\\s\\\\]+SELECT)",
|
||||||
|
"([\\w\\\\]+[\\s]*<=)",
|
||||||
|
"([\\w\\\\]+[\\s]*:=)",
|
||||||
|
"FOR\\s+[\\w\\s,]+:\\s*\\w+\\s+USE",
|
||||||
|
"REPORT"
|
||||||
|
];
|
||||||
|
let newLineAfterKeyWordsStr = blockStartsKeyWords.join("|");
|
||||||
|
let regexBlockMidKeyWords = blockMidKeyWords.convertToRegexBlockWords();
|
||||||
|
let regexBlockStartsKeywords = new RegExp("([\\w]+\\s*:\\s*)?(" + newLineAfterKeyWordsStr + ")([^\\w]|$)");
|
||||||
|
let regexBlockEndsKeyWords = blockEndsKeyWords.convertToRegexBlockWords();
|
||||||
|
let regexBlockIndentedEndsKeyWords = indentedEndsKeyWords.convertToRegexBlockWords();
|
||||||
|
let regexblockEndsWithSemicolon = blockEndsWithSemicolon.convertToRegexBlockWords();
|
||||||
|
let regexMidKeyWhen = "WHEN".convertToRegexBlockWords();
|
||||||
|
let regexMidKeyElse = "ELSE|ELSIF".convertToRegexBlockWords();
|
||||||
|
if (endIndex == null) {
|
||||||
|
endIndex = inputs.length - 1;
|
||||||
|
}
|
||||||
|
for (i = startIndex; i <= endIndex; i++) {
|
||||||
|
if (indent < 0) {
|
||||||
|
indent = 0;
|
||||||
|
}
|
||||||
|
let input = inputs[i].trim();
|
||||||
|
if (input.regexStartsWith(regexBlockIndentedEndsKeyWords)) {
|
||||||
|
result.push(new FormattedLine(input, indent));
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
if (input.regexStartsWith(/COMPONENT\s/)) {
|
||||||
|
let modeCache = Mode;
|
||||||
|
Mode = FormatMode.EndsWithSemicolon;
|
||||||
|
[i, endIndex] = beautifyComponentBlock(inputs, result, settings, i, endIndex, indent);
|
||||||
|
Mode = modeCache;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (input.regexStartsWith(/PACKAGE[\s\w]+IS\s+NEW/)) {
|
||||||
|
let modeCache = Mode;
|
||||||
|
Mode = FormatMode.EndsWithSemicolon;
|
||||||
|
[i, endIndex] = beautifyPackageIsNewBlock(inputs, result, settings, i, endIndex, indent);
|
||||||
|
Mode = modeCache;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (input.regexStartsWith(/\w+\s*:\s*ENTITY/)) {
|
||||||
|
let modeCache = Mode;
|
||||||
|
Mode = FormatMode.EndsWithSemicolon;
|
||||||
|
[i, endIndex] = beautifySemicolonBlock(inputs, result, settings, i, endIndex, indent);
|
||||||
|
Mode = modeCache;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexblockEndsWithSemicolon)) {
|
||||||
|
let modeCache = Mode;
|
||||||
|
Mode = FormatMode.EndsWithSemicolon;
|
||||||
|
[i, endIndex] = beautifySemicolonBlock(inputs, result, settings, i, endIndex, indent);
|
||||||
|
Mode = modeCache;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (input.regexStartsWith(/(.+:\s*)?(CASE)([\s]|$)/)) {
|
||||||
|
let modeCache = Mode;
|
||||||
|
Mode = FormatMode.CaseWhen;
|
||||||
|
i = beautifyCaseBlock(inputs, result, settings, i, indent);
|
||||||
|
Mode = modeCache;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (input.regexStartsWith(/.*?\:\=\s*\($/)) {
|
||||||
|
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, ":=");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (input.regexStartsWith(/[\w\s:]*\bPORT\b([\s]|$)/)) {
|
||||||
|
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "PORT");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (input.regexStartsWith(/TYPE\s+\w+\s+IS\s+\(/)) {
|
||||||
|
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "IS");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (input.regexStartsWith(/[\w\s:]*GENERIC([\s]|$)/)) {
|
||||||
|
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "GENERIC");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (input.regexStartsWith(/[\w\s:]*PROCEDURE[\s\w]+\($/)) {
|
||||||
|
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "PROCEDURE");
|
||||||
|
if (inputs[i].regexStartsWith(/.*\)[\s]*IS/)) {
|
||||||
|
i = beautify3(inputs, result, settings, i + 1, indent + 1);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (input.regexStartsWith(/FUNCTION[^\w]/)
|
||||||
|
&& input.regexIndexOf(/[^\w]RETURN[^\w]/) < 0) {
|
||||||
|
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "FUNCTION");
|
||||||
|
if (!inputs[i].regexStartsWith(regexBlockEndsKeyWords)) {
|
||||||
|
i = beautify3(inputs, result, settings, i + 1, indent + 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result[i].Indent++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (input.regexStartsWith(/IMPURE FUNCTION[^\w]/)
|
||||||
|
&& input.regexIndexOf(/[^\w]RETURN[^\w]/) < 0) {
|
||||||
|
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "IMPURE FUNCTION");
|
||||||
|
if (!inputs[i].regexStartsWith(regexBlockEndsKeyWords)) {
|
||||||
|
if (inputs[i].regexStartsWith(regexBlockIndentedEndsKeyWords)) {
|
||||||
|
result[i].Indent++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
i = beautify3(inputs, result, settings, i + 1, indent + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result[i].Indent++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.push(new FormattedLine(input, indent));
|
||||||
|
if (startIndex != 0
|
||||||
|
&& (input.regexStartsWith(regexBlockMidKeyWords)
|
||||||
|
|| (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexMidKeyElse))
|
||||||
|
|| (Mode == FormatMode.CaseWhen && input.regexStartsWith(regexMidKeyWhen)))) {
|
||||||
|
result[i].Indent--;
|
||||||
|
}
|
||||||
|
else if (startIndex != 0
|
||||||
|
&& (input.regexStartsWith(regexBlockEndsKeyWords))) {
|
||||||
|
result[i].Indent--;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
if (input.regexStartsWith(regexOneLineBlockKeyWords)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (input.regexStartsWith(regexFunctionMultiLineBlockKeyWords)
|
||||||
|
|| input.regexStartsWith(regexBlockStartsKeywords)) {
|
||||||
|
i = beautify3(inputs, result, settings, i + 1, indent + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i--;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
exports.beautify3 = beautify3;
|
||||||
|
function ReserveSemicolonInKeywords(arr) {
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
if (arr[i].match(/FUNCTION|PROCEDURE/) != null) {
|
||||||
|
arr[i] = arr[i].replace(/;/g, ILSemicolon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function ApplyNoNewLineAfter(arr, noNewLineAfter) {
|
||||||
|
if (noNewLineAfter == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
noNewLineAfter.forEach(n => {
|
||||||
|
let regex = new RegExp("(" + n.toUpperCase + ")[ a-z0-9]+[a-z0-9]+");
|
||||||
|
if (arr[i].regexIndexOf(regex) >= 0) {
|
||||||
|
arr[i] += "@@singleline";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.ApplyNoNewLineAfter = ApplyNoNewLineAfter;
|
||||||
|
function RemoveAsserts(arr) {
|
||||||
|
let need_semi = false;
|
||||||
|
let inAssert = false;
|
||||||
|
let n = 0;
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
let has_semi = arr[i].indexOf(";") >= 0;
|
||||||
|
if (need_semi) {
|
||||||
|
arr[i] = '';
|
||||||
|
}
|
||||||
|
n = arr[i].indexOf("ASSERT ");
|
||||||
|
if (n >= 0) {
|
||||||
|
inAssert = true;
|
||||||
|
arr[i] = '';
|
||||||
|
}
|
||||||
|
if (!has_semi) {
|
||||||
|
if (inAssert) {
|
||||||
|
need_semi = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
need_semi = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.RemoveAsserts = RemoveAsserts;
|
||||||
|
function escapeText(arr, regex, escapedChar) {
|
||||||
|
let quotes = [];
|
||||||
|
let regexEpr = new RegExp(regex, "g");
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
let matches = arr[i].match(regexEpr);
|
||||||
|
if (matches != null) {
|
||||||
|
for (var j = 0; j < matches.length; j++) {
|
||||||
|
var match = matches[j];
|
||||||
|
arr[i] = arr[i].replace(match, escapedChar.repeat(match.length));
|
||||||
|
quotes.push(match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return quotes;
|
||||||
|
}
|
||||||
|
function RemoveExtraNewLines(input) {
|
||||||
|
input = input.replace(/(?:\r\n|\r|\n)/g, '\r\n');
|
||||||
|
input = input.replace(/ \r\n/g, '\r\n');
|
||||||
|
input = input.replace(/\r\n\r\n\r\n/g, '\r\n');
|
||||||
|
return input;
|
||||||
|
}
|
35
resources/formatter/vlogFormatter.js
Normal file
35
resources/formatter/vlogFormatter.js
Normal file
File diff suppressed because one or more lines are too long
5
resources/hdlParser/index.d.ts
vendored
5
resources/hdlParser/index.d.ts
vendored
@ -12,10 +12,7 @@ interface Fast {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface All {
|
interface All {
|
||||||
content: {
|
content: RawSymbol[]
|
||||||
error: string[]
|
|
||||||
symbols: RawSymbol[]
|
|
||||||
}
|
|
||||||
languageId: HdlLangID
|
languageId: HdlLangID
|
||||||
macro: Macro
|
macro: Macro
|
||||||
}
|
}
|
||||||
|
@ -546,7 +546,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"include": {
|
"include": {
|
||||||
"prefix": "inc",
|
"prefix": "include",
|
||||||
"body": [
|
"body": [
|
||||||
"`include \"$1\""
|
"`include \"$1\""
|
||||||
],
|
],
|
||||||
@ -554,9 +554,9 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"define": {
|
"define": {
|
||||||
"prefix": "def",
|
"prefix": "define",
|
||||||
"body": [
|
"body": [
|
||||||
"`def $1 = $2"
|
"`define $1 $2"
|
||||||
],
|
],
|
||||||
"description": "`define var = val"
|
"description": "`define var = val"
|
||||||
},
|
},
|
||||||
@ -902,5 +902,23 @@
|
|||||||
"}",
|
"}",
|
||||||
"*/"
|
"*/"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"dumpfile": {
|
||||||
|
"prefix": "$dumpfile",
|
||||||
|
"body": [
|
||||||
|
"\\$dumpfile(\"$1\");"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dumpvars": {
|
||||||
|
"prefix": "$dumpvars",
|
||||||
|
"body": [
|
||||||
|
"\\$dumpvars;"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"finish": {
|
||||||
|
"prefix": "$finish",
|
||||||
|
"body": [
|
||||||
|
"\\$finish;"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,17 +3,19 @@ import * as vscode from 'vscode';
|
|||||||
import { opeParam, MainOutput, ReportType } from './global';
|
import { opeParam, MainOutput, ReportType } from './global';
|
||||||
import { hdlParam } from './hdlParser';
|
import { hdlParam } from './hdlParser';
|
||||||
import { prjManage, registerManagerCommands } from './manager';
|
import { prjManage, registerManagerCommands } from './manager';
|
||||||
import { registerFunctionCommands } from './function';
|
import { registerFunctionCommands, registerLsp } from './function';
|
||||||
|
|
||||||
async function registerCommand(context: vscode.ExtensionContext) {
|
async function registerCommand(context: vscode.ExtensionContext) {
|
||||||
registerFunctionCommands(context);
|
registerFunctionCommands(context);
|
||||||
registerManagerCommands(context);
|
registerManagerCommands(context);
|
||||||
|
registerLsp(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function launch(context: vscode.ExtensionContext) {
|
async function launch(context: vscode.ExtensionContext) {
|
||||||
await prjManage.initialise(context);
|
await prjManage.initialise(context);
|
||||||
await registerCommand(context);
|
await registerCommand(context);
|
||||||
|
|
||||||
|
|
||||||
MainOutput.report('Digital-IDE has launched, Version: 0.3.0');
|
MainOutput.report('Digital-IDE has launched, Version: 0.3.0');
|
||||||
MainOutput.report('OS: ' + opeParam.os);
|
MainOutput.report('OS: ' + opeParam.os);
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,18 @@ import * as hdlDoc from './hdlDoc';
|
|||||||
import * as sim from './sim';
|
import * as sim from './sim';
|
||||||
import * as treeView from './treeView';
|
import * as treeView from './treeView';
|
||||||
|
|
||||||
|
import * as lspCompletion from './lsp/completion';
|
||||||
|
import * as lspDocSymbol from './lsp/docSymbol';
|
||||||
|
import * as lspDefinition from './lsp/definition';
|
||||||
|
import * as lspHover from './lsp/hover';
|
||||||
|
import * as lspFormatter from '../../resources/formatter';
|
||||||
|
|
||||||
function registerDocumentation(context: vscode.ExtensionContext) {
|
function registerDocumentation(context: vscode.ExtensionContext) {
|
||||||
vscode.commands.registerCommand('digital-ide.hdlDoc.showWebview', hdlDoc.showDocWebview);
|
vscode.commands.registerCommand('digital-ide.hdlDoc.showWebview', hdlDoc.showDocWebview);
|
||||||
hdlDoc.registerFileDocExport(context);
|
hdlDoc.registerFileDocExport(context);
|
||||||
hdlDoc.registerProjectDocExport(context);
|
hdlDoc.registerProjectDocExport(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function registerSimulation(context: vscode.ExtensionContext) {
|
function registerSimulation(context: vscode.ExtensionContext) {
|
||||||
vscode.commands.registerCommand('digital-ide.tool.instance', sim.instantiation);
|
vscode.commands.registerCommand('digital-ide.tool.instance', sim.instantiation);
|
||||||
vscode.commands.registerCommand('digital-ide.tool.testbench', sim.testbench);
|
vscode.commands.registerCommand('digital-ide.tool.testbench', sim.testbench);
|
||||||
@ -42,6 +47,29 @@ function registerTreeView(context: vscode.ExtensionContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function registerLsp(context: vscode.ExtensionContext) {
|
||||||
|
const vlogSelector: vscode.DocumentSelector = {scheme: 'file', language: 'verilog'};
|
||||||
|
const svlogSelector: vscode.DocumentSelector = {scheme: 'file', language: 'systemverilog'};
|
||||||
|
const vhdlSelector: vscode.DocumentSelector = {scheme: 'file', language: 'vhdl'};
|
||||||
|
|
||||||
|
// formatter
|
||||||
|
vscode.languages.registerDocumentFormattingEditProvider(vlogSelector, lspFormatter.hdlFormatterProvider);
|
||||||
|
vscode.languages.registerDocumentFormattingEditProvider(vhdlSelector, lspFormatter.hdlFormatterProvider);
|
||||||
|
vscode.languages.registerDocumentFormattingEditProvider(svlogSelector, lspFormatter.hdlFormatterProvider);
|
||||||
|
|
||||||
|
// verilog lsp
|
||||||
|
vscode.languages.registerDocumentSymbolProvider(vlogSelector, lspDocSymbol.vlogDocSymbolProvider);
|
||||||
|
vscode.languages.registerDefinitionProvider(vlogSelector, lspDefinition.vlogDefinitionProvider);
|
||||||
|
vscode.languages.registerHoverProvider(vlogSelector, lspHover.vlogHoverProvider);
|
||||||
|
vscode.languages.registerCompletionItemProvider(vlogSelector, lspCompletion.vlogIncludeCompletionProvider, '/', '"');
|
||||||
|
vscode.languages.registerCompletionItemProvider(vlogSelector, lspCompletion.vlogMacroCompletionProvider, '`');
|
||||||
|
vscode.languages.registerCompletionItemProvider(vlogSelector, lspCompletion.vlogPositionPortProvider, '.');
|
||||||
|
vscode.languages.registerCompletionItemProvider(vlogSelector, lspCompletion.vlogCompletionProvider);
|
||||||
|
// vhdl lsp
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
registerFunctionCommands
|
registerFunctionCommands,
|
||||||
|
registerLsp
|
||||||
};
|
};
|
8
src/function/lsp/completion/index.ts
Normal file
8
src/function/lsp/completion/index.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { vlogCompletionProvider, vlogIncludeCompletionProvider, vlogMacroCompletionProvider, vlogPositionPortProvider } from './vlog';
|
||||||
|
|
||||||
|
export {
|
||||||
|
vlogCompletionProvider,
|
||||||
|
vlogIncludeCompletionProvider,
|
||||||
|
vlogMacroCompletionProvider,
|
||||||
|
vlogPositionPortProvider
|
||||||
|
};
|
303
src/function/lsp/completion/vlog.ts
Normal file
303
src/function/lsp/completion/vlog.ts
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
import * as util from '../util';
|
||||||
|
import { hdlFile, hdlPath } from '../../../hdlFs';
|
||||||
|
import { hdlParam, HdlSymbol } from '../../../hdlParser';
|
||||||
|
import { AbsPath, MainOutput, ReportType } from '../../../global';
|
||||||
|
import { Define, Include, RawSymbol } from '../../../hdlParser/common';
|
||||||
|
import { HdlInstance, HdlModule } from '../../../hdlParser/core';
|
||||||
|
import { vlogKeyword } from '../util/keyword';
|
||||||
|
|
||||||
|
class VlogIncludeCompletionProvider implements vscode.CompletionItemProvider {
|
||||||
|
public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList<vscode.CompletionItem>> {
|
||||||
|
try {
|
||||||
|
const items = this.provideIncludeFiles(document, position);
|
||||||
|
return items;
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private provideIncludeFiles(document: vscode.TextDocument, position: vscode.Position): vscode.CompletionItem[] {
|
||||||
|
if (position.character === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const filePath = hdlPath.toSlash(document.fileName);
|
||||||
|
const lineText = document.lineAt(position).text;
|
||||||
|
|
||||||
|
let firstQIndex = lineText.lastIndexOf('"', position.character - 1);
|
||||||
|
let lastQIndex = lineText.indexOf('"', position.character);
|
||||||
|
|
||||||
|
if (firstQIndex !== -1 && lastQIndex !== -1) {
|
||||||
|
const currentPath = lineText.substring(firstQIndex + 1, lastQIndex);
|
||||||
|
const folderName = currentPath.length === 0 ? '.' : currentPath;
|
||||||
|
const folderAbsPath = hdlPath.rel2abs(filePath, folderName);
|
||||||
|
return this.filterIncludeFiles(folderAbsPath, filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private filterIncludeFiles(folderPath: AbsPath, currentPath: AbsPath) {
|
||||||
|
if (fs.existsSync(folderPath)) {
|
||||||
|
const suggestFiles = [];
|
||||||
|
for (const fileName of fs.readdirSync(folderPath)) {
|
||||||
|
const filePath = hdlPath.join(folderPath, fileName);
|
||||||
|
if (filePath === currentPath) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stat = fs.statSync(filePath);
|
||||||
|
const clItem = new vscode.CompletionItem(fileName);
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
clItem.kind = vscode.CompletionItemKind.Folder;
|
||||||
|
} else if (stat.isFile()) {
|
||||||
|
clItem.kind = vscode.CompletionItemKind.File;
|
||||||
|
}
|
||||||
|
suggestFiles.push(clItem);
|
||||||
|
}
|
||||||
|
return suggestFiles;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class VlogMacroCompletionProvider implements vscode.CompletionItemProvider {
|
||||||
|
public async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): Promise<vscode.CompletionItem[] | vscode.CompletionList<vscode.CompletionItem> | null | undefined> {
|
||||||
|
try {
|
||||||
|
const targetWordRange = document.getWordRangeAtPosition(position, /[`_0-9a-zA-Z]+/);
|
||||||
|
const targetWord = document.getText(targetWordRange);
|
||||||
|
const filePath = document.fileName;
|
||||||
|
const symbolResult = await HdlSymbol.all(filePath);
|
||||||
|
if (!symbolResult) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = this.provideMacros(targetWord, symbolResult.macro.defines);
|
||||||
|
return items;
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private provideMacros(targetWord: string, defines: Define[]): vscode.CompletionItem[] {
|
||||||
|
const suggestMacros: vscode.CompletionItem[] = [];
|
||||||
|
if (!defines || defines.length === 0) {
|
||||||
|
return suggestMacros;
|
||||||
|
}
|
||||||
|
for (const define of defines) {
|
||||||
|
const name = '`' + define.name;
|
||||||
|
const clItem = new vscode.CompletionItem(name, vscode.CompletionItemKind.Constant);
|
||||||
|
clItem.detail = 'macro ' + define.replacement;
|
||||||
|
clItem.insertText = targetWord.startsWith('`') ? define.name : name;
|
||||||
|
suggestMacros.push(clItem);
|
||||||
|
}
|
||||||
|
return suggestMacros;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class VlogPositionPortProvider implements vscode.CompletionItemProvider {
|
||||||
|
public async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): Promise<vscode.CompletionItem[] | vscode.CompletionList<vscode.CompletionItem> | null | undefined> {
|
||||||
|
try {
|
||||||
|
const suggestPositionPorts: vscode.CompletionItem[] = [];
|
||||||
|
const filePath = hdlPath.toSlash(document.fileName);
|
||||||
|
const symbolResult = await HdlSymbol.all(filePath);
|
||||||
|
if (!symbolResult) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const scopeSymbols = util.filterSymbolScope(position, symbolResult.content);
|
||||||
|
if (!scopeSymbols ||
|
||||||
|
!scopeSymbols.module ||
|
||||||
|
!scopeSymbols.symbols ||
|
||||||
|
!hdlParam.hasHdlModule(filePath, scopeSymbols.module.name)) {
|
||||||
|
return suggestPositionPorts;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentModule = hdlParam.getHdlModule(filePath, scopeSymbols.module.name);
|
||||||
|
if (!currentModule) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentInst = util.filterInstanceByPosition(position, scopeSymbols.symbols, currentModule);
|
||||||
|
// find instance and instMod is not null (solve the dependence already)
|
||||||
|
|
||||||
|
if (currentInst && currentInst.module && currentInst.instModPath) {
|
||||||
|
const portsparams = this.providePositionPorts(position, currentInst);
|
||||||
|
suggestPositionPorts.push(...portsparams);
|
||||||
|
}
|
||||||
|
|
||||||
|
return suggestPositionPorts;
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private providePositionPorts(position: vscode.Position, currentInst: HdlInstance): vscode.CompletionItem[] {
|
||||||
|
if (!currentInst.module) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = currentInst.instparams;
|
||||||
|
const ports = currentInst.instports;
|
||||||
|
|
||||||
|
if (params &&
|
||||||
|
util.positionAfterEqual(position, params.start) &&
|
||||||
|
util.positionAfterEqual(params.end, position)) {
|
||||||
|
|
||||||
|
return currentInst.module.params.map(param => {
|
||||||
|
const clItem = new vscode.CompletionItem(param.name, vscode.CompletionItemKind.Constant);
|
||||||
|
clItem.detail = 'param';
|
||||||
|
return clItem;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (ports &&
|
||||||
|
util.positionAfterEqual(position, ports.start) &&
|
||||||
|
util.positionAfterEqual(ports.end, position)) {
|
||||||
|
|
||||||
|
return currentInst.module.ports.map(port => {
|
||||||
|
const clItem = new vscode.CompletionItem(port.name, vscode.CompletionItemKind.Interface);
|
||||||
|
clItem.detail = 'port';
|
||||||
|
return clItem;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VlogCompletionProvider implements vscode.CompletionItemProvider {
|
||||||
|
public async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): Promise<vscode.CompletionItem[] | vscode.CompletionList<vscode.CompletionItem> | null | undefined> {
|
||||||
|
try {
|
||||||
|
const filePath = hdlPath.toSlash(document.fileName);
|
||||||
|
|
||||||
|
// 1. provide keyword
|
||||||
|
const completions = this.getKeyWordItem();
|
||||||
|
|
||||||
|
const symbolResult = await HdlSymbol.all(filePath);
|
||||||
|
if (!symbolResult) {
|
||||||
|
return completions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(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 getKeyWordItem(): vscode.CompletionItem[] {
|
||||||
|
const vlogKeywordItem = [];
|
||||||
|
for (const keyword of vlogKeyword.keys()) {
|
||||||
|
const clItem = this.makekeywordCompletionItem(keyword);
|
||||||
|
vlogKeywordItem.push(clItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vlogKeywordItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
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$1end"); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return clItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async provideModules(filePath: AbsPath, includes: Include[]): Promise<vscode.CompletionItem[]> {
|
||||||
|
const suggestModules: vscode.CompletionItem[] = [];
|
||||||
|
|
||||||
|
// TODO : add `include xxx automatically
|
||||||
|
for (const module of hdlParam.getAllHdlModules()) {
|
||||||
|
const clItem = new vscode.CompletionItem(module.name, vscode.CompletionItemKind.Class);
|
||||||
|
clItem.detail = 'module';
|
||||||
|
suggestModules.push(clItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return suggestModules;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async provideParamsPorts(module: HdlModule): Promise<vscode.CompletionItem[]> {
|
||||||
|
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<vscode.CompletionItem[]> {
|
||||||
|
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.detail = symbol.type;
|
||||||
|
suggestNets.push(clItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return suggestNets;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const vlogCompletionProvider = new VlogCompletionProvider();
|
||||||
|
const vlogIncludeCompletionProvider = new VlogIncludeCompletionProvider();
|
||||||
|
const vlogMacroCompletionProvider = new VlogMacroCompletionProvider();
|
||||||
|
const vlogPositionPortProvider = new VlogPositionPortProvider();
|
||||||
|
|
||||||
|
export {
|
||||||
|
vlogCompletionProvider,
|
||||||
|
vlogIncludeCompletionProvider,
|
||||||
|
vlogMacroCompletionProvider,
|
||||||
|
vlogPositionPortProvider
|
||||||
|
};
|
5
src/function/lsp/definition/index.ts
Normal file
5
src/function/lsp/definition/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { vlogDefinitionProvider } from './vlog';
|
||||||
|
|
||||||
|
export {
|
||||||
|
vlogDefinitionProvider
|
||||||
|
};
|
161
src/function/lsp/definition/vlog.ts
Normal file
161
src/function/lsp/definition/vlog.ts
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
import * as vsctm from 'vscode-textmate';
|
||||||
|
|
||||||
|
import { hdlPath } from '../../../hdlFs';
|
||||||
|
import { hdlParam, HdlSymbol } from '../../../hdlParser';
|
||||||
|
import { All } from '../../../../resources/hdlParser';
|
||||||
|
import { vlogKeyword } from '../util/keyword';
|
||||||
|
import * as util from '../util';
|
||||||
|
import { MainOutput, ReportType } from '../../../global';
|
||||||
|
|
||||||
|
|
||||||
|
class VlogDefinitionProvider implements vscode.DefinitionProvider {
|
||||||
|
|
||||||
|
public async provideDefinition(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Location | vscode.LocationLink[] | null> {
|
||||||
|
// get current words
|
||||||
|
const wordRange = document.getWordRangeAtPosition(position, /[`_0-9A-Za-z]+/);
|
||||||
|
if (!wordRange) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const targetWord = document.getText(wordRange);
|
||||||
|
|
||||||
|
// check if need skip
|
||||||
|
if (this.needSkip(document, position, targetWord)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filePath = document.fileName;
|
||||||
|
const vlogAll = await HdlSymbol.all(filePath);
|
||||||
|
if (!vlogAll) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
const location = await this.makeDefinition(document, position, vlogAll, targetWord, wordRange);
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private needSkip(document: vscode.TextDocument, position: vscode.Position, targetWord: string): boolean {
|
||||||
|
// check keyword
|
||||||
|
if (vlogKeyword.isKeyword(targetWord)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check comment
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async makeDefinition(document: vscode.TextDocument, position: vscode.Position, all: All, targetWord: string, targetWordRange: vscode.Range): Promise<vscode.Location | vscode.LocationLink[] | null> {
|
||||||
|
const filePath = hdlPath.toSlash(document.fileName);
|
||||||
|
const lineText = document.lineAt(position).text;
|
||||||
|
|
||||||
|
// match `include
|
||||||
|
const includeResult = util.matchInclude(document, position, all.macro.includes);
|
||||||
|
if (includeResult) {
|
||||||
|
const absPath = hdlPath.rel2abs(filePath, includeResult.name);
|
||||||
|
const targetFile = vscode.Uri.file(absPath);
|
||||||
|
const targetPosition = new vscode.Position(0, 0);
|
||||||
|
const targetRange = new vscode.Range(targetPosition, targetPosition);
|
||||||
|
const originSelectionRange = document.getWordRangeAtPosition(position, /[\."_0-9a-zA-Z]+/);
|
||||||
|
const link: vscode.LocationLink = { targetUri: targetFile, targetRange, originSelectionRange };
|
||||||
|
return [link];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// match macro
|
||||||
|
const macroResult = util.matchDefineMacro(position, targetWord, all.macro.defines);
|
||||||
|
if (macroResult) {
|
||||||
|
const targetRange = util.transformRange(macroResult.range, -1, -1);
|
||||||
|
const link: vscode.LocationLink = { targetUri: document.uri, targetRange: targetRange, originSelectionRange: targetWordRange };
|
||||||
|
return [link];
|
||||||
|
}
|
||||||
|
|
||||||
|
// locate at one module
|
||||||
|
const scopeSymbols = util.filterSymbolScope(position, all.content);
|
||||||
|
if (!scopeSymbols || !scopeSymbols.module) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const currentModule = hdlParam.getHdlModule(filePath, scopeSymbols.module.name);
|
||||||
|
if (!currentModule) {
|
||||||
|
MainOutput.report('Fail to get HdlModule ' + filePath + ' ' + scopeSymbols.module.name, ReportType.Debug);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// match instance
|
||||||
|
const instResult = util.matchInstance(targetWord, currentModule);
|
||||||
|
if (instResult) {
|
||||||
|
const instModule = instResult.module;
|
||||||
|
if (!instModule || !instResult.instModPath) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const targetFile = vscode.Uri.file(instResult.instModPath);
|
||||||
|
const targetRange = util.transformRange(instModule.range, -1, 0, 1);
|
||||||
|
const link: vscode.LocationLink = { targetUri: targetFile, targetRange };
|
||||||
|
return [link];
|
||||||
|
}
|
||||||
|
|
||||||
|
// match port or param definition (position input)
|
||||||
|
if (util.isPositionInput(lineText, position.character)) {
|
||||||
|
const currentInstResult = util.filterInstanceByPosition(position, scopeSymbols.symbols, currentModule);
|
||||||
|
if (!currentInstResult || !currentInstResult.instModPath) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const instParamPromise = util.getInstParamByPosition(currentInstResult, position, targetWord);
|
||||||
|
const instPortPromise = util.getInstPortByPosition(currentInstResult, position, targetWord);
|
||||||
|
|
||||||
|
const instParam = await instParamPromise;
|
||||||
|
const instPort = await instPortPromise;
|
||||||
|
const instModPathUri = vscode.Uri.file(currentInstResult.instModPath);
|
||||||
|
|
||||||
|
if (instParam) {
|
||||||
|
const targetRange = util.transformRange(instParam.range, -1, 0);
|
||||||
|
const link: vscode.LocationLink = { targetUri: instModPathUri, targetRange };
|
||||||
|
return [link];
|
||||||
|
}
|
||||||
|
if (instPort) {
|
||||||
|
const targetRange = util.transformRange(instPort.range, -1, 0);
|
||||||
|
const link: vscode.LocationLink = { targetUri: instModPathUri, targetRange };
|
||||||
|
return [link];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// match params
|
||||||
|
const paramResult = util.matchParams(targetWord, currentModule);
|
||||||
|
|
||||||
|
if (paramResult) {
|
||||||
|
const targetRange = util.transformRange(paramResult.range, -1, 0);
|
||||||
|
const link: vscode.LocationLink = { targetUri: document.uri, targetRange };
|
||||||
|
return [link];
|
||||||
|
}
|
||||||
|
|
||||||
|
// match ports
|
||||||
|
const portResult = util.matchPorts(targetWord, currentModule);
|
||||||
|
|
||||||
|
if (portResult) {
|
||||||
|
const targetRange = util.transformRange(portResult.range, -1, 0);
|
||||||
|
const link: vscode.LocationLink = { targetUri: document.uri, targetRange };
|
||||||
|
return [link];
|
||||||
|
}
|
||||||
|
|
||||||
|
// match others
|
||||||
|
const normalResult = util.matchNormalSymbol(targetWord, scopeSymbols.symbols);
|
||||||
|
if (normalResult) {
|
||||||
|
const targetRange = util.transformRange(normalResult.range, -1, 0);
|
||||||
|
|
||||||
|
console.log(targetRange, normalResult);
|
||||||
|
|
||||||
|
const link: vscode.LocationLink = { targetUri: document.uri, targetRange };
|
||||||
|
return [link];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const vlogDefinitionProvider = new VlogDefinitionProvider();
|
||||||
|
|
||||||
|
export {
|
||||||
|
vlogDefinitionProvider
|
||||||
|
};
|
@ -0,0 +1,6 @@
|
|||||||
|
import { vlogDocSymbolProvider } from './vlog';
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
vlogDocSymbolProvider
|
||||||
|
};
|
@ -1,37 +1,36 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
|
import { AllowNull } from '../../../global';
|
||||||
import { HdlSymbol } from '../../../hdlParser';
|
import { HdlSymbol } from '../../../hdlParser';
|
||||||
|
import { RawSymbol, makeVscodePosition, Range } from '../../../hdlParser/common';
|
||||||
|
|
||||||
|
import { positionAfterEqual } from '../util';
|
||||||
|
|
||||||
|
interface DocSymbolContainer {
|
||||||
|
docSymbol: AllowNull<vscode.DocumentSymbol>,
|
||||||
|
range: AllowNull<Range>
|
||||||
|
};
|
||||||
|
|
||||||
class VlogDocSymbolProvider implements vscode.DocumentSymbolProvider {
|
class VlogDocSymbolProvider implements vscode.DocumentSymbolProvider {
|
||||||
|
public async provideDocumentSymbols(document: vscode.TextDocument, token: vscode.CancellationToken): Promise<vscode.DocumentSymbol[]> {
|
||||||
|
const path = document.fileName;
|
||||||
|
const vlogAll = await HdlSymbol.all(path);
|
||||||
|
|
||||||
public provideDocumentSymbols(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.ProviderResult<vscode.SymbolInformation[] | vscode.DocumentSymbol[]> {
|
if (!vlogAll || !vlogAll.content) {
|
||||||
const code = document.getText();
|
|
||||||
const symbolResult = HdlSymbol.all(code);
|
|
||||||
const symbols = symbolResult.symbols;
|
|
||||||
|
|
||||||
if (!symbols) {
|
|
||||||
return [];
|
return [];
|
||||||
}
|
} else {
|
||||||
try {
|
const symbols = vlogAll.content;
|
||||||
const symbolInfos = this.makeSymbolInfos(document, symbols);
|
const symbolInfos = this.makeDocumentSymbols(document, symbols);
|
||||||
return symbolInfos;
|
return symbolInfos;
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
private makeDocumentSymbols(document: vscode.TextDocument, symbols: RawSymbol[]): vscode.DocumentSymbol[] {
|
||||||
* @param {vscode.TextDocument} document
|
const docSymbols = [];
|
||||||
* @param {Array<SymbolResult>} symbols
|
|
||||||
* @returns {Array<vscode.DocumentSymbol>}
|
|
||||||
*/
|
|
||||||
makeSymbolInfos(document: vscode.TextDocument, symbols: SymbolResult[]) {
|
|
||||||
let docSymbols = [];
|
|
||||||
const visitedSymbols = new Set();
|
const visitedSymbols = new Set();
|
||||||
const moduleSymbols = symbols.filter(symbol => {
|
const moduleSymbols = symbols.filter(symbol => {
|
||||||
if (symbol.type == 'module') {
|
if (symbol.type === 'module') {
|
||||||
visitedSymbols.add(symbol);
|
visitedSymbols.add(symbol);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -41,38 +40,43 @@ class VlogDocSymbolProvider implements vscode.DocumentSymbolProvider {
|
|||||||
for (const moduleSymbol of moduleSymbols) {
|
for (const moduleSymbol of moduleSymbols) {
|
||||||
const moduleName = moduleSymbol.name;
|
const moduleName = moduleSymbol.name;
|
||||||
const moduleKind = this.getSymbolKind(moduleSymbol.type);
|
const moduleKind = this.getSymbolKind(moduleSymbol.type);
|
||||||
const moduleRange = new vscode.Range(moduleSymbol.start, moduleSymbol.end);
|
const moduleStart = new vscode.Position(moduleSymbol.range.start.line - 1, moduleSymbol.range.start.character);
|
||||||
|
const moduleEnd = new vscode.Position(moduleSymbol.range.end.line - 1, moduleSymbol.range.start.character);
|
||||||
|
const moduleRange = new vscode.Range(moduleStart, moduleEnd);
|
||||||
const moduleDocSymbol = new vscode.DocumentSymbol(moduleName,
|
const moduleDocSymbol = new vscode.DocumentSymbol(moduleName,
|
||||||
moduleName,
|
moduleName,
|
||||||
moduleKind,
|
moduleKind,
|
||||||
moduleRange,
|
moduleRange,
|
||||||
moduleRange);
|
moduleRange);
|
||||||
docSymbols.push(moduleDocSymbol);
|
docSymbols.push(moduleDocSymbol);
|
||||||
let paramContainer = {
|
const paramContainer: DocSymbolContainer = {
|
||||||
docSymbol: null,
|
docSymbol: null,
|
||||||
range: null
|
range: null
|
||||||
};
|
};
|
||||||
let portContainer = {
|
const portContainer: DocSymbolContainer = {
|
||||||
docSymbol: null,
|
docSymbol: null,
|
||||||
range: null
|
range: null
|
||||||
};
|
};
|
||||||
|
const portTypes = ['input', 'inout', 'output'];
|
||||||
|
|
||||||
// make others in module inner
|
// make others in module inner
|
||||||
for (const symbol of symbols) {
|
for (const symbol of symbols) {
|
||||||
if (visitedSymbols.has(symbol)) {
|
if (visitedSymbols.has(symbol)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!(positionAfterEqual(symbol.start, moduleSymbol.start) &&
|
if (!(positionAfterEqual(symbol.range.start, moduleSymbol.range.start) &&
|
||||||
positionAfterEqual(moduleSymbol.end, symbol.end))) {
|
positionAfterEqual(moduleSymbol.range.end, symbol.range.end))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!symbol.name) {
|
if (!symbol.name) {
|
||||||
symbol.name = '???';
|
symbol.name = '???';
|
||||||
}
|
}
|
||||||
visitedSymbols.add(symbol);
|
visitedSymbols.add(symbol);
|
||||||
const symbolRange = new vscode.Range(symbol.start, symbol.end);
|
const symbolStart = new vscode.Position(symbol.range.start.line - 1, symbol.range.start.character);
|
||||||
|
const symbolEnd = new vscode.Position(symbol.range.end.line - 1, symbol.range.end.character);
|
||||||
|
const symbolRange = new vscode.Range(symbolStart, symbolEnd);
|
||||||
|
|
||||||
if (symbol.type == 'parameter') {
|
if (symbol.type === 'parameter') {
|
||||||
if (!paramContainer.range) {
|
if (!paramContainer.range) {
|
||||||
paramContainer.range = symbolRange;
|
paramContainer.range = symbolRange;
|
||||||
paramContainer.docSymbol = new vscode.DocumentSymbol('param',
|
paramContainer.docSymbol = new vscode.DocumentSymbol('param',
|
||||||
@ -87,9 +91,9 @@ class VlogDocSymbolProvider implements vscode.DocumentSymbolProvider {
|
|||||||
vscode.SymbolKind.Constant,
|
vscode.SymbolKind.Constant,
|
||||||
symbolRange,
|
symbolRange,
|
||||||
symbolRange);
|
symbolRange);
|
||||||
paramContainer.docSymbol.children.push(paramDocSymbol);
|
paramContainer.docSymbol?.children.push(paramDocSymbol);
|
||||||
|
|
||||||
} else if (['input', 'inout', 'output'].includes(symbol.type)) {
|
} else if (portTypes.includes(symbol.type)) {
|
||||||
if (!portContainer.range) {
|
if (!portContainer.range) {
|
||||||
portContainer.range = symbolRange;
|
portContainer.range = symbolRange;
|
||||||
portContainer.docSymbol = new vscode.DocumentSymbol('port',
|
portContainer.docSymbol = new vscode.DocumentSymbol('port',
|
||||||
@ -105,7 +109,7 @@ class VlogDocSymbolProvider implements vscode.DocumentSymbolProvider {
|
|||||||
vscode.SymbolKind.Interface,
|
vscode.SymbolKind.Interface,
|
||||||
symbolRange,
|
symbolRange,
|
||||||
symbolRange);
|
symbolRange);
|
||||||
portContainer.docSymbol.children.push(portDocSymbol);
|
portContainer.docSymbol?.children.push(portDocSymbol);
|
||||||
} else {
|
} else {
|
||||||
const symbolKind = this.getSymbolKind(symbol.type);
|
const symbolKind = this.getSymbolKind(symbol.type);
|
||||||
const symbolDocSymbol = new vscode.DocumentSymbol(symbol.name,
|
const symbolDocSymbol = new vscode.DocumentSymbol(symbol.name,
|
||||||
@ -122,8 +126,8 @@ class VlogDocSymbolProvider implements vscode.DocumentSymbolProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getSymbolKind(name) {
|
getSymbolKind(name: string): vscode.SymbolKind {
|
||||||
if (name.indexOf('[') != -1) {
|
if (name.indexOf('[') !== -1) {
|
||||||
return vscode.SymbolKind.Array;
|
return vscode.SymbolKind.Array;
|
||||||
}
|
}
|
||||||
switch (name) {
|
switch (name) {
|
||||||
@ -176,12 +180,11 @@ class VlogDocSymbolProvider implements vscode.DocumentSymbolProvider {
|
|||||||
case 'bit': return vscode.SymbolKind.Boolean;
|
case 'bit': return vscode.SymbolKind.Boolean;
|
||||||
default: return vscode.SymbolKind.Event;
|
default: return vscode.SymbolKind.Event;
|
||||||
}
|
}
|
||||||
/* Unused/Free SymbolKind icons
|
|
||||||
return SymbolKind.Number;
|
|
||||||
return SymbolKind.Enum;
|
|
||||||
return SymbolKind.EnumMember;
|
|
||||||
return SymbolKind.Operator;
|
|
||||||
return SymbolKind.Array;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const vlogDocSymbolProvider = new VlogDocSymbolProvider();
|
||||||
|
|
||||||
|
export {
|
||||||
|
vlogDocSymbolProvider
|
||||||
|
};
|
5
src/function/lsp/hover/index.ts
Normal file
5
src/function/lsp/hover/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { vlogHoverProvider } from './vlog';
|
||||||
|
|
||||||
|
export {
|
||||||
|
vlogHoverProvider
|
||||||
|
};
|
193
src/function/lsp/hover/vlog.ts
Normal file
193
src/function/lsp/hover/vlog.ts
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
|
import { hdlDir, hdlPath } from '../../../hdlFs';
|
||||||
|
import { hdlParam, HdlSymbol } from '../../../hdlParser';
|
||||||
|
import { All } from '../../../../resources/hdlParser';
|
||||||
|
import { vlogKeyword } from '../util/keyword';
|
||||||
|
import * as util from '../util';
|
||||||
|
import { MainOutput, ReportType } from '../../../global';
|
||||||
|
import { HdlLangID } from '../../../global/enum';
|
||||||
|
|
||||||
|
|
||||||
|
class VlogHoverProvider implements vscode.HoverProvider {
|
||||||
|
public async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Hover | null> {
|
||||||
|
// get current words
|
||||||
|
const wordRange = document.getWordRangeAtPosition(position, /[`_0-9A-Za-z]+/);
|
||||||
|
if (!wordRange) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const targetWord = document.getText(wordRange);
|
||||||
|
|
||||||
|
// check if need skip
|
||||||
|
if (this.needSkip(document, position, targetWord)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filePath = document.fileName;
|
||||||
|
const vlogAll = await HdlSymbol.all(filePath);
|
||||||
|
if (!vlogAll) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
const hover = await this.makeHover(document, position, vlogAll, targetWord, wordRange);
|
||||||
|
return hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private needSkip(document: vscode.TextDocument, position: vscode.Position, targetWord: string): boolean {
|
||||||
|
// check keyword
|
||||||
|
if (vlogKeyword.isKeyword(targetWord)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check comment
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async makeHover(document: vscode.TextDocument, position: vscode.Position, all: All, targetWord: string, targetWordRange: vscode.Range): Promise<vscode.Hover | null> {
|
||||||
|
const lineText = document.lineAt(position).text;
|
||||||
|
const filePath = hdlPath.toSlash(document.fileName);
|
||||||
|
|
||||||
|
// total content rendered on the hover box
|
||||||
|
const content = new vscode.MarkdownString('', true);
|
||||||
|
|
||||||
|
// match `include
|
||||||
|
const includeResult = util.matchInclude(document, position, all.macro.includes);
|
||||||
|
if (includeResult) {
|
||||||
|
const absPath = hdlPath.rel2abs(filePath, includeResult.name);
|
||||||
|
content.appendCodeblock(`"${absPath}"`, HdlLangID.Verilog);
|
||||||
|
const targetRange = document.getWordRangeAtPosition(position, /[1-9a-zA-Z_\.]+/);
|
||||||
|
return new vscode.Hover(content, targetRange);
|
||||||
|
} else if (lineText.trim().startsWith('`include')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// match macro
|
||||||
|
const macroResult = util.matchDefineMacro(position, targetWord, all.macro.defines);
|
||||||
|
if (macroResult) {
|
||||||
|
const name = macroResult.name;
|
||||||
|
const value = macroResult.value;
|
||||||
|
content.appendCodeblock(`\`define ${name} ${value}`, HdlLangID.Verilog);
|
||||||
|
return new vscode.Hover(content, targetWordRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
// locate at one module
|
||||||
|
const scopeSymbols = util.filterSymbolScope(position, all.content);
|
||||||
|
if (!scopeSymbols || !scopeSymbols.module || !hdlParam.hasHdlModule(filePath, scopeSymbols.module.name)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const currentModule = hdlParam.getHdlModule(filePath, scopeSymbols.module.name);
|
||||||
|
if (!currentModule) {
|
||||||
|
MainOutput.report('Fail to get HdlModule ' + filePath + ' ' + scopeSymbols.module.name, ReportType.Debug);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// match instance
|
||||||
|
const instResult = util.matchInstance(targetWord, currentModule);
|
||||||
|
if (instResult) {
|
||||||
|
const instModule = instResult.module;
|
||||||
|
if (!instModule || !instResult.instModPath) {
|
||||||
|
content.appendMarkdown('cannot find the definition of the module');
|
||||||
|
return new vscode.Hover(content);
|
||||||
|
}
|
||||||
|
await util.makeVlogHoverContent(content, instModule);
|
||||||
|
return new vscode.Hover(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// match port or param definition (position input)
|
||||||
|
if (util.isPositionInput(lineText, position.character)) {
|
||||||
|
const currentInstResult = util.filterInstanceByPosition(position, scopeSymbols.symbols, currentModule);
|
||||||
|
if (!currentInstResult || !currentInstResult.instModPath) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const instParamPromise = util.getInstParamByPosition(currentInstResult, position, targetWord);
|
||||||
|
const instPortPromise = util.getInstPortByPosition(currentInstResult, position, targetWord);
|
||||||
|
|
||||||
|
const instParam = await instParamPromise;
|
||||||
|
const instPort = await instPortPromise;
|
||||||
|
|
||||||
|
if (instParam) {
|
||||||
|
const paramComment = await util.searchCommentAround(currentInstResult.instModPath, instParam.range);
|
||||||
|
const paramDesc = util.makeParamDesc(instParam);
|
||||||
|
content.appendCodeblock(paramDesc, HdlLangID.Verilog);
|
||||||
|
if (paramComment) {
|
||||||
|
content.appendCodeblock(paramComment, HdlLangID.Verilog);
|
||||||
|
}
|
||||||
|
return new vscode.Hover(content);
|
||||||
|
}
|
||||||
|
if (instPort) {
|
||||||
|
const portComment = await util.searchCommentAround(currentInstResult.instModPath, instPort.range);
|
||||||
|
const portDesc = util.makePortDesc(instPort);
|
||||||
|
content.appendCodeblock(portDesc, HdlLangID.Verilog);
|
||||||
|
if (portComment) {
|
||||||
|
content.appendCodeblock(portComment, HdlLangID.Verilog);
|
||||||
|
}
|
||||||
|
return new vscode.Hover(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// match params
|
||||||
|
const paramResult = util.matchParams(targetWord, currentModule);
|
||||||
|
if (paramResult) {
|
||||||
|
const paramComment = await util.searchCommentAround(filePath, paramResult.range);
|
||||||
|
const paramDesc = util.makeParamDesc(paramResult);
|
||||||
|
content.appendCodeblock(paramDesc, HdlLangID.Verilog);
|
||||||
|
if (paramComment) {
|
||||||
|
content.appendCodeblock(paramComment, HdlLangID.Verilog);
|
||||||
|
}
|
||||||
|
return new vscode.Hover(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
// match ports
|
||||||
|
const portResult = util.matchPorts(targetWord, currentModule);
|
||||||
|
if (portResult) {
|
||||||
|
const portComment = await util.searchCommentAround(filePath, portResult.range);
|
||||||
|
const portDesc = util.makePortDesc(portResult);
|
||||||
|
content.appendCodeblock(portDesc, HdlLangID.Verilog);
|
||||||
|
if (portComment) {
|
||||||
|
content.appendCodeblock(portComment, HdlLangID.Verilog);
|
||||||
|
}
|
||||||
|
return new vscode.Hover(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
// match others
|
||||||
|
const normalResult = util.matchNormalSymbol(targetWord, scopeSymbols.symbols);
|
||||||
|
if (normalResult) {
|
||||||
|
const normalComment = await util.searchCommentAround(filePath, normalResult.range);
|
||||||
|
const normalDesc = util.makeNormalDesc(normalResult);
|
||||||
|
|
||||||
|
console.log(normalResult);
|
||||||
|
|
||||||
|
|
||||||
|
content.appendCodeblock(normalDesc, HdlLangID.Verilog);
|
||||||
|
if (normalComment) {
|
||||||
|
content.appendCodeblock(normalComment, HdlLangID.Verilog);
|
||||||
|
}
|
||||||
|
return new vscode.Hover(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// feature 1. number signed and unsigned number display
|
||||||
|
const numberResult = util.transferVlogNumber(lineText, position.character);
|
||||||
|
if (numberResult) {
|
||||||
|
const bits = targetWord.length - 1;
|
||||||
|
content.appendCodeblock(bits + "'" + targetWord, HdlLangID.Verilog);
|
||||||
|
content.appendMarkdown("`unsigned` " + numberResult.unsigned);
|
||||||
|
content.appendText('\n');
|
||||||
|
content.appendMarkdown("`signed` " + numberResult.signed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new vscode.Hover(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const vlogHoverProvider = new VlogHoverProvider();
|
||||||
|
|
||||||
|
export {
|
||||||
|
vlogHoverProvider
|
||||||
|
};
|
@ -1,203 +0,0 @@
|
|||||||
const vscode = require('vscode');
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const HDLPath = require('../../../HDLfilesys/operation/path');
|
|
||||||
const { HDLParam, Module, SymbolResult, Instance } = require('../../../HDLparser');
|
|
||||||
const { positionAfterEqual } = require('./index');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} folderPath
|
|
||||||
* @param {string} currentPath
|
|
||||||
* @returns {Array<vscode.CompletionItem>}
|
|
||||||
*/
|
|
||||||
function filterIncludeFiles(folderPath, currentPath) {
|
|
||||||
if (fs.existsSync(folderPath)) {
|
|
||||||
const suggestFiles = [];
|
|
||||||
for (const fileName of fs.readdirSync(folderPath)) {
|
|
||||||
const filePath = HDLPath.join(folderPath, fileName);
|
|
||||||
if (filePath === currentPath) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const stat = fs.statSync(filePath);
|
|
||||||
const clItem = new vscode.CompletionItem(fileName);
|
|
||||||
if (stat.isDirectory()) {
|
|
||||||
clItem.kind = vscode.CompletionItemKind.Folder;
|
|
||||||
} else if (stat.isFile()) {
|
|
||||||
clItem.kind = vscode.CompletionItemKind.File;
|
|
||||||
}
|
|
||||||
suggestFiles.push(clItem);
|
|
||||||
}
|
|
||||||
return suggestFiles;
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {vscode.TextDocument} document
|
|
||||||
* @param {vscode.Position} position
|
|
||||||
* @returns {Array<vscode.CompletionItem>}
|
|
||||||
*/
|
|
||||||
function provideIncludeFiles(document, position) {
|
|
||||||
if (position.character == 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const filePath = HDLPath.toSlash(document.fileName);
|
|
||||||
const lineText = document.lineAt(position).text;
|
|
||||||
|
|
||||||
let firstQIndex = lineText.lastIndexOf('"', position.character - 1);
|
|
||||||
let lastQIndex = lineText.indexOf('"', position.character);
|
|
||||||
|
|
||||||
if (firstQIndex != -1 && lastQIndex != -1) {
|
|
||||||
const currentPath = lineText.substring(firstQIndex + 1, lastQIndex);
|
|
||||||
const folderName = currentPath.length == 0 ? '.' : currentPath;
|
|
||||||
const folderAbsPath = HDLPath.rel2abs(filePath, folderName);
|
|
||||||
return filterIncludeFiles(folderAbsPath, filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} singleWord
|
|
||||||
* @param {object} defines
|
|
||||||
* @returns {Promise<Array<vscode.CompletionItem>>}
|
|
||||||
*/
|
|
||||||
function provideMacros(singleWord, defines) {
|
|
||||||
const suggestMacros = [];
|
|
||||||
if (!defines) {
|
|
||||||
return suggestMacros;
|
|
||||||
}
|
|
||||||
for (const macro of Object.keys(defines)) {
|
|
||||||
const value = defines[macro].value;
|
|
||||||
const name = '`' + macro;
|
|
||||||
const clItem = new vscode.CompletionItem('`' + macro, vscode.CompletionItemKind.Constant)
|
|
||||||
clItem.detail = 'macro ' + value;
|
|
||||||
if (singleWord[0] == '`') {
|
|
||||||
clItem.insertText = macro;
|
|
||||||
} else {
|
|
||||||
clItem.insertText = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
suggestMacros.push(clItem);
|
|
||||||
}
|
|
||||||
return suggestMacros;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {vscode.Position} position cursor position
|
|
||||||
* @param {Instance} currentInst
|
|
||||||
* @returns {Promise<Array<vscode.CompletionItem>>}
|
|
||||||
*/
|
|
||||||
function providePositionPorts(position, currentInst) {
|
|
||||||
const params = currentInst.instparams;
|
|
||||||
const ports = currentInst.instports;
|
|
||||||
console.log(position);
|
|
||||||
console.log(params);
|
|
||||||
console.log(ports);
|
|
||||||
|
|
||||||
if (params &&
|
|
||||||
positionAfterEqual(position, params.start) &&
|
|
||||||
positionAfterEqual(params.end, position)) {
|
|
||||||
|
|
||||||
return currentInst.module.params.map(param => {
|
|
||||||
const clItem = new vscode.CompletionItem(param.name, vscode.CompletionItemKind.Constant);
|
|
||||||
clItem.detail = 'param';
|
|
||||||
return clItem;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (ports &&
|
|
||||||
positionAfterEqual(position, ports.start) &&
|
|
||||||
positionAfterEqual(ports.end, position)) {
|
|
||||||
|
|
||||||
return currentInst.module.ports.map(port => {
|
|
||||||
const clItem = new vscode.CompletionItem(port.name, vscode.CompletionItemKind.Interface);
|
|
||||||
clItem.detail = 'port';
|
|
||||||
return clItem;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description provide module of the current module and include module
|
|
||||||
* @param {string} filePath
|
|
||||||
* @param {object} includes {path: range}
|
|
||||||
* @returns {Promise<Array<vscode.CompletionItem>>}
|
|
||||||
*/
|
|
||||||
async function provideModules(filePath, includes) {
|
|
||||||
// support include of all the module
|
|
||||||
// use command property to auto add include path
|
|
||||||
const suggestModules = [];
|
|
||||||
|
|
||||||
if (!includes) {
|
|
||||||
return suggestModules;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const module of HDLParam.getAllModules()) {
|
|
||||||
const clItem = new vscode.CompletionItem(module.name, vscode.CompletionItemKind.Class);
|
|
||||||
clItem.detail = 'module';
|
|
||||||
suggestModules.push(clItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return suggestModules;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Module} module
|
|
||||||
* @returns {Promise<Array<vscode.CompletionItem>>}
|
|
||||||
*/
|
|
||||||
async function provideParamsPorts(module) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Array<SymbolResult>} symbols
|
|
||||||
* @returns {Promise<Array<vscode.CompletionItem>>}
|
|
||||||
*/
|
|
||||||
async function provideNets(symbols) {
|
|
||||||
if (!symbols) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const suggestNets = [];
|
|
||||||
for (const symbol of symbols) {
|
|
||||||
if (symbol.type == 'net') {
|
|
||||||
const clItem = new vscode.CompletionItem(symbol.name, vscode.CompletionItemKind.Variable);
|
|
||||||
clItem.detail = 'net';
|
|
||||||
suggestNets.push(clItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return suggestNets;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
provideIncludeFiles,
|
|
||||||
provideMacros,
|
|
||||||
providePositionPorts,
|
|
||||||
provideModules,
|
|
||||||
provideParamsPorts,
|
|
||||||
provideNets
|
|
||||||
};
|
|
@ -126,14 +126,8 @@ function bin2float(bin: string, exp: number, fra: number): number | undefined {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getFullSymbolInfo(document: vscode.TextDocument, range: Range, nonblank: RegExp, l_comment_symbol: string, l_comment_regExp: RegExp, needDefinition=true) {
|
async function getFullSymbolInfo(document: vscode.TextDocument, range: Range, nonblank: RegExp, l_comment_symbol: string, l_comment_regExp: RegExp) {
|
||||||
const comments = [];
|
const comments = [];
|
||||||
if (needDefinition) {
|
|
||||||
const startPosition = new vscode.Position(range.start.line, range.start.character);
|
|
||||||
const endPosition = new vscode.Position(range.end.line, range.end.character);
|
|
||||||
const definitionString = document.getText(new vscode.Range(startPosition, endPosition));
|
|
||||||
comments.push(definitionString);
|
|
||||||
}
|
|
||||||
|
|
||||||
let content = '';
|
let content = '';
|
||||||
let is_b_comment = false;
|
let is_b_comment = false;
|
||||||
@ -212,7 +206,13 @@ async function getFullSymbolInfo(document: vscode.TextDocument, range: Range, no
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return comments.reverse().join('');
|
// 清除空前行
|
||||||
|
let resultComment = '';
|
||||||
|
for (const c of comments.reverse()) {
|
||||||
|
resultComment += c.trim() + '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultComment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -220,8 +220,8 @@ async function getFullSymbolInfo(document: vscode.TextDocument, range: Range, no
|
|||||||
* @param path
|
* @param path
|
||||||
* @param range
|
* @param range
|
||||||
*/
|
*/
|
||||||
async function getSymbolComment(path: AbsPath, range: Range) {
|
async function getSymbolComment(path: AbsPath, range: Range): Promise<string | null> {
|
||||||
let languageId = hdlFile.getLanguageId(path);
|
const languageId = hdlFile.getLanguageId(path);
|
||||||
const uri = vscode.Uri.file(path);
|
const uri = vscode.Uri.file(path);
|
||||||
const documentPromise = vscode.workspace.openTextDocument(uri);
|
const documentPromise = vscode.workspace.openTextDocument(uri);
|
||||||
|
|
||||||
@ -229,14 +229,15 @@ async function getSymbolComment(path: AbsPath, range: Range) {
|
|||||||
const nonblank = /\S+/g;
|
const nonblank = /\S+/g;
|
||||||
const l_comment = getCommentUtilByLanguageId(languageId);
|
const l_comment = getCommentUtilByLanguageId(languageId);
|
||||||
if (l_comment) {
|
if (l_comment) {
|
||||||
let l_comment_symbol = l_comment.l_comment_symbol;
|
const l_comment_symbol = l_comment.l_comment_symbol;
|
||||||
let l_comment_regExp = l_comment.l_comment_regExp;
|
const l_comment_regExp = l_comment.l_comment_regExp;
|
||||||
|
|
||||||
// add definition first
|
// add definition first
|
||||||
const document = await documentPromise;
|
const document = await documentPromise;
|
||||||
return await getFullSymbolInfo(document, range, nonblank, l_comment_symbol, l_comment_regExp);
|
const symbolInfo = await getFullSymbolInfo(document, range, nonblank, l_comment_symbol, l_comment_regExp);
|
||||||
|
return symbolInfo;
|
||||||
}
|
}
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -263,7 +264,7 @@ async function getSymbolComments(path: string, ranges: Range[]): Promise<string[
|
|||||||
const commentPromises = [];
|
const commentPromises = [];
|
||||||
const comments = [];
|
const comments = [];
|
||||||
for (const range of ranges) {
|
for (const range of ranges) {
|
||||||
const commentP = getFullSymbolInfo(document, range, nonblank, l_comment_symbol, l_comment_regExp, false);
|
const commentP = getFullSymbolInfo(document, range, nonblank, l_comment_symbol, l_comment_regExp);
|
||||||
commentPromises.push(commentP);
|
commentPromises.push(commentP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,570 +0,0 @@
|
|||||||
const vscode = require('vscode');
|
|
||||||
|
|
||||||
const { transferVlogNumber, getSymbolComment, getSymbolComments } = require('./feature');
|
|
||||||
|
|
||||||
const { SymbolResult, Position, CommentResult, Range, Module, Instance,
|
|
||||||
HDLParam, ModPort, ModParam } = require('../../../HDLparser');
|
|
||||||
|
|
||||||
const vlogKeyword = new Set([
|
|
||||||
'`include', '`define', 'input', 'output', 'inout', 'module', 'endmodule',
|
|
||||||
'wire', 'reg', 'parameter', 'always', 'assign', 'if', 'else', 'begin', 'end',
|
|
||||||
'case', 'endcase', 'posedge', 'negedge', 'or', 'default', 'while', 'and', '`timescale',
|
|
||||||
'or', 'xor', 'initial', 'function', 'endfunction', 'force', 'pulldown'
|
|
||||||
]);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {Array<vscode.CompletionItem>}
|
|
||||||
*/
|
|
||||||
function getVlogKeywordItem() {
|
|
||||||
const vlogKeywordItem = [];
|
|
||||||
for (const keyword of vlogKeyword) {
|
|
||||||
const clItem = new vscode.CompletionItem(keyword, vscode.CompletionItemKind.Keyword);
|
|
||||||
clItem.detail = "keyword";
|
|
||||||
vlogKeywordItem.push(clItem);
|
|
||||||
}
|
|
||||||
return vlogKeywordItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {string} singleWord
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
function isVlogKeyword(singleWord) {
|
|
||||||
return vlogKeyword.has(singleWord);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description get the last single word in current line
|
|
||||||
* @param {string} prefixString
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function getLastSingleWord(prefixString) {
|
|
||||||
prefixString = prefixString.trim();
|
|
||||||
const length = prefixString.length;
|
|
||||||
if (length == 0) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
const wordCharacters = [];
|
|
||||||
let alphaReg = /[`_0-9A-Za-z]/;
|
|
||||||
for (let i = length - 1; i >= 0; -- i) {
|
|
||||||
const ch = prefixString[i];
|
|
||||||
if (alphaReg.test(ch)) {
|
|
||||||
wordCharacters.push(ch);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return wordCharacters.reverse().join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description get the single word at hover
|
|
||||||
* @param {string} lineText
|
|
||||||
* @param {number} character
|
|
||||||
*/
|
|
||||||
function getSingleWordAtCurrentPosition(lineText, character) {
|
|
||||||
let alphaReg = /[`_0-9A-Za-z]/;
|
|
||||||
if (alphaReg.test(lineText[character])) {
|
|
||||||
const leftPart = [];
|
|
||||||
const rightPart = [];
|
|
||||||
const length = lineText.length;
|
|
||||||
for (let i = character - 1; i >= 0; -- i) {
|
|
||||||
const ch = lineText[i];
|
|
||||||
if (alphaReg.test(ch)) {
|
|
||||||
leftPart.push(ch);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = character + 1; i < length; ++ i) {
|
|
||||||
const ch = lineText[i];
|
|
||||||
if (alphaReg.test(ch)) {
|
|
||||||
rightPart.push(ch);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const leftWord = leftPart.reverse().join('');
|
|
||||||
const rightWord = rightPart.join('');
|
|
||||||
return leftWord + lineText[character] + rightWord;
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Position} position_a
|
|
||||||
* @param {Position} position_b
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
function positionAfter(position_a, position_b) {
|
|
||||||
return position_a.line > position_b.line || (
|
|
||||||
position_a.line == position_b.line &&
|
|
||||||
position_a.character > position_b.character);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Position} position_a
|
|
||||||
* @param {Position} position_b
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
function positionEqual(position_a, position_b) {
|
|
||||||
return position_a.line == position_b.line &&
|
|
||||||
position_a.character == position_b.character;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description position_a behind or equal to position_b
|
|
||||||
* @param {Position} position_a
|
|
||||||
* @param {Position} position_b
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
function positionAfterEqual(position_a, position_b) {
|
|
||||||
return positionAfter(position_a, position_b) ||
|
|
||||||
positionEqual(position_a, position_b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description filter the symbol result item that exceed the scope
|
|
||||||
* @param {vscode.Position} position
|
|
||||||
* @param {Array<SymbolResult>} symbolResults
|
|
||||||
* @returns {{module : SymbolResult, symbols : Array<SymbolResult>}}
|
|
||||||
*/
|
|
||||||
function filterSymbolScope(position, symbolResults) {
|
|
||||||
if (!symbolResults) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const parentModules = symbolResults.filter(item =>
|
|
||||||
item.type == 'module' &&
|
|
||||||
positionAfterEqual(position, item.start) &&
|
|
||||||
positionAfterEqual(item.end, position)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (parentModules.length == 0) {
|
|
||||||
// TODO : macro
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const parentModule = parentModules[0];
|
|
||||||
const symbols = symbolResults.filter(item =>
|
|
||||||
item != parentModule &&
|
|
||||||
positionAfterEqual(item.start, parentModule.start) &&
|
|
||||||
positionAfterEqual(parentModule.end, item.end));
|
|
||||||
|
|
||||||
return {
|
|
||||||
module : parentModule,
|
|
||||||
symbols : symbols
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {vscode.TextDocument} document
|
|
||||||
* @param {Position} position
|
|
||||||
* @param {Array<CommentResult>} comments
|
|
||||||
*/
|
|
||||||
function isInComment(document, position, comments) {
|
|
||||||
if (!comments) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// remove the situation that <cursor> // comment
|
|
||||||
const lineText = document.lineAt(position).text;
|
|
||||||
const singleCommentIndex = lineText.indexOf('//');
|
|
||||||
if (singleCommentIndex != -1) {
|
|
||||||
return position.character >= singleCommentIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentLine = position.line + 1;
|
|
||||||
for (const comment of comments) {
|
|
||||||
const commentLine = comment.start.line;
|
|
||||||
if (commentLine > currentLine) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const startPosition = new vscode.Position(commentLine, 0);
|
|
||||||
const startOffset = document.offsetAt(startPosition);
|
|
||||||
const endPosition = document.positionAt(startOffset + comment.length);
|
|
||||||
|
|
||||||
const originalPosition = new Position(currentLine, position.character);
|
|
||||||
|
|
||||||
if (positionAfterEqual(originalPosition, startPosition) &&
|
|
||||||
positionAfterEqual(endPosition, originalPosition)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {vscode.Position} position
|
|
||||||
* @param {object} includes
|
|
||||||
* @returns {{name: string, start: Position, end: Position}}
|
|
||||||
*/
|
|
||||||
function matchInclude(position, includes) {
|
|
||||||
if (!includes) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (const includeString of Object.keys(includes)) {
|
|
||||||
const range = includes[includeString];
|
|
||||||
// TODO : remove - 1 if bug is fixed
|
|
||||||
range.start.line -= 1;
|
|
||||||
range.end.line -= 1;
|
|
||||||
if (positionAfterEqual(position, range.start) &&
|
|
||||||
positionAfterEqual(range.end, position)) {
|
|
||||||
|
|
||||||
return {
|
|
||||||
name : includeString,
|
|
||||||
start: range.start,
|
|
||||||
end: range.end
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {vscode.Position} position
|
|
||||||
* @param {string} singleWord
|
|
||||||
* @param {object} defines
|
|
||||||
* @returns {{name: string, value: any, range: Range}}
|
|
||||||
*/
|
|
||||||
function matchDefine(position, defines) {
|
|
||||||
if (!defines) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const macro of Object.keys(defines)) {
|
|
||||||
const range = defines[macro].range;
|
|
||||||
range.start.line -= 1;
|
|
||||||
range.end.line -= 1;
|
|
||||||
if (positionAfterEqual(position, range.start) &&
|
|
||||||
positionAfterEqual(range.end, position)) {
|
|
||||||
return {
|
|
||||||
name : macro,
|
|
||||||
value: defines[macro].value,
|
|
||||||
range: range
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {vscode.Position} position
|
|
||||||
* @param {string} singleWord
|
|
||||||
* @param {object} defines
|
|
||||||
* @returns {{name: string, value: any, range: Range}}
|
|
||||||
*/
|
|
||||||
function matchDefineMacro(position, singleWord, defines) {
|
|
||||||
if (!defines) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (singleWord[0] != '`' || singleWord.length <= 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const targetMacro = singleWord.substring(1);
|
|
||||||
for (const macro of Object.keys(defines)) {
|
|
||||||
if (macro == targetMacro) {
|
|
||||||
const range = defines[macro].range;
|
|
||||||
const value = defines[macro].value;
|
|
||||||
// TODO : remove - 1 if bug is fixed
|
|
||||||
range.start.line -= 1;
|
|
||||||
range.end.line -= 1;
|
|
||||||
return {
|
|
||||||
name : macro,
|
|
||||||
value : value,
|
|
||||||
range : range
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} singleWord single word to be matched
|
|
||||||
* @param {Module} module
|
|
||||||
* @returns {Instance}
|
|
||||||
*/
|
|
||||||
function matchInstance(singleWord, module) {
|
|
||||||
if (!module) {
|
|
||||||
console.log('warning, cannot locate module', singleWord);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const inst of module.getInstances()) {
|
|
||||||
if (singleWord == inst.type) {
|
|
||||||
return inst;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {vscode.Position} position current cursor position
|
|
||||||
* @param {Array<SymbolResult>} symbols all the symbols in the wrapper module
|
|
||||||
* @param {Module} module wrapper module
|
|
||||||
* @param {Instance}
|
|
||||||
*/
|
|
||||||
function filterInstanceByPosition(position, symbols, module) {
|
|
||||||
if (!symbols) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (const symbol of symbols) {
|
|
||||||
const inst = module.findInstance(symbol.name);
|
|
||||||
if (positionAfterEqual(position, symbol.start) &&
|
|
||||||
positionAfterEqual(symbol.end, position) &&
|
|
||||||
inst) {
|
|
||||||
return inst;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Instance} inst
|
|
||||||
* @param {vscode.Position} position
|
|
||||||
* @param {string} singleWord
|
|
||||||
* @returns {Promise<ModPort>}
|
|
||||||
*/
|
|
||||||
async function getInstPortByPosition(inst, position, singleWord) {
|
|
||||||
if (!inst.module || !inst.instports) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (positionAfterEqual(position, inst.instports.start) &&
|
|
||||||
positionAfterEqual(inst.instports.end, position)) {
|
|
||||||
for (const port of inst.module.ports) {
|
|
||||||
if (port.name == singleWord) {
|
|
||||||
return port;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Instance} inst
|
|
||||||
* @param {vscode.Position} position
|
|
||||||
* @param {string} singleWord
|
|
||||||
* @returns {Promise<ModParam>}
|
|
||||||
*/
|
|
||||||
async function getInstParamByPosition(inst, position, singleWord) {
|
|
||||||
if (!inst.module || !inst.instparams) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (positionAfterEqual(position, inst.instparams.start) &&
|
|
||||||
positionAfterEqual(inst.instparams.end, position)) {
|
|
||||||
for (const param of inst.module.params) {
|
|
||||||
if (param.name == singleWord) {
|
|
||||||
return param;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} lineText
|
|
||||||
* @param {number} character
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
function isPositionInput(lineText, character) {
|
|
||||||
let alphaReg = /[_0-9A-Za-z]/;
|
|
||||||
for (let i = character; i >= 0; -- i) {
|
|
||||||
const ch = lineText[i];
|
|
||||||
if (alphaReg.test(ch)) {
|
|
||||||
continue;
|
|
||||||
} else if (ch == '.') {
|
|
||||||
if (i == 0) {
|
|
||||||
return true;
|
|
||||||
} else if (lineText[i - 1] == ' ') {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} singleWord
|
|
||||||
* @param {Module} module
|
|
||||||
* @returns {ModPort}
|
|
||||||
*/
|
|
||||||
function matchPorts(singleWord, module) {
|
|
||||||
if (!module || module.ports.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const targetPorts = module.ports.filter(port => port.name == singleWord);
|
|
||||||
if (targetPorts.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return targetPorts[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} singleWord
|
|
||||||
* @param {Module} module
|
|
||||||
* @returns {ModParam}
|
|
||||||
*/
|
|
||||||
function matchParams(singleWord, module) {
|
|
||||||
if (!module || module.params.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const targetParams = module.params.filter(param => param.name == singleWord);
|
|
||||||
if (targetParams.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return targetParams[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {ModPort} port
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function makePortDesc(port) {
|
|
||||||
let portDesc = port.type;
|
|
||||||
if (port.width) {
|
|
||||||
portDesc += ' ' + port.width;
|
|
||||||
}
|
|
||||||
portDesc += ' ' + port.name;
|
|
||||||
return portDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {ModParam} param
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function makeParamDesc(param) {
|
|
||||||
let paramDesc = 'parameter ' + param.name;
|
|
||||||
if (param.init) {
|
|
||||||
paramDesc += ' = ' + param.init;
|
|
||||||
}
|
|
||||||
return paramDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} singleWord
|
|
||||||
* @param {Array<SymbolResult>} symbols
|
|
||||||
* @returns {SymbolResult}
|
|
||||||
*/
|
|
||||||
function matchNormalSymbol(singleWord, symbols) {
|
|
||||||
if (!symbols || Object.keys(symbols).length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (const symbol of symbols) {
|
|
||||||
if (singleWord == symbol.name) {
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {vscode.MarkdownString} content
|
|
||||||
* @param {Module} module
|
|
||||||
*/
|
|
||||||
async function makeVlogHoverContent(content, module) {
|
|
||||||
const portNum = module.ports.length;
|
|
||||||
const paramNum = module.params.length;
|
|
||||||
const instNum = module.getInstanceNum();
|
|
||||||
|
|
||||||
const moduleUri = vscode.Uri.file(module.path);
|
|
||||||
const thenableFileDocument = vscode.workspace.openTextDocument(moduleUri);
|
|
||||||
|
|
||||||
const portDesc = paramNum + ' $(instance-param) ' +
|
|
||||||
portNum + ' $(instance-port) ' +
|
|
||||||
instNum + ' $(instance-module)';
|
|
||||||
|
|
||||||
|
|
||||||
content.appendCodeblock('module ' + module.name, 'verilog');
|
|
||||||
content.appendText('\n');
|
|
||||||
content.appendMarkdown(portDesc);
|
|
||||||
content.appendText(' | ');
|
|
||||||
|
|
||||||
const count = {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
inout: 0
|
|
||||||
};
|
|
||||||
for (const port of module.ports) {
|
|
||||||
count[port.type] += 1;
|
|
||||||
}
|
|
||||||
const ioDesc = count.input + ' $(instance-input) ' +
|
|
||||||
count.output + ' $(instance-output) ' +
|
|
||||||
count.inout + ' $(instance-inout)';
|
|
||||||
content.appendMarkdown(ioDesc);
|
|
||||||
content.appendText('\n');
|
|
||||||
|
|
||||||
content.appendMarkdown('---');
|
|
||||||
|
|
||||||
// make document
|
|
||||||
const fileDocument = await thenableFileDocument;
|
|
||||||
const range = new vscode.Range(module.range.start, module.range.end);
|
|
||||||
const moduleDefinitionCode = fileDocument.getText(range);
|
|
||||||
content.appendCodeblock(moduleDefinitionCode, 'verilog');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async function searchCommentAround(uri, range) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getVlogKeywordItem,
|
|
||||||
getLastSingleWord,
|
|
||||||
getSingleWordAtCurrentPosition,
|
|
||||||
filterSymbolScope,
|
|
||||||
filterInstanceByPosition,
|
|
||||||
isPositionInput,
|
|
||||||
isInComment,
|
|
||||||
matchInclude,
|
|
||||||
matchDefine,
|
|
||||||
matchDefineMacro,
|
|
||||||
matchInstance,
|
|
||||||
matchPorts,
|
|
||||||
matchParams,
|
|
||||||
matchNormalSymbol,
|
|
||||||
isVlogKeyword,
|
|
||||||
makeVlogHoverContent,
|
|
||||||
positionAfterEqual,
|
|
||||||
getInstPortByPosition,
|
|
||||||
getInstParamByPosition,
|
|
||||||
makePortDesc,
|
|
||||||
makeParamDesc,
|
|
||||||
transferVlogNumber,
|
|
||||||
getSymbolComment,
|
|
||||||
getSymbolComments
|
|
||||||
};
|
|
408
src/function/lsp/util/index.ts
Normal file
408
src/function/lsp/util/index.ts
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
|
import { transferVlogNumber, getSymbolComment, getSymbolComments } from './feature';
|
||||||
|
|
||||||
|
import { AbsPath, AllowNull } from '../../../global';
|
||||||
|
import { Position, Range, HdlModulePort, HdlModuleParam, CommentResult, RawSymbol, Define, Include, makeVscodePosition } from '../../../hdlParser/common';
|
||||||
|
import { HdlModule, HdlInstance, hdlParam } from '../../../hdlParser/core';
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
const Unknown = 'Unknown';
|
||||||
|
|
||||||
|
interface MatchedSymbol {
|
||||||
|
name: string,
|
||||||
|
value: any,
|
||||||
|
range: Range
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
interface ModuleScope {
|
||||||
|
module: RawSymbol,
|
||||||
|
symbols: RawSymbol[]
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function transformRange(range: Range | vscode.Range, lineOffset: number = 0, characterOffset: number = 0,
|
||||||
|
endLineOffset: number | undefined = undefined, endCharacterOffset: number | undefined = undefined): vscode.Range {
|
||||||
|
const start = range.start;
|
||||||
|
const end = range.end;
|
||||||
|
const startPosition = new vscode.Position(start.line + lineOffset, start.character + characterOffset);
|
||||||
|
endLineOffset = endLineOffset ? endLineOffset : lineOffset;
|
||||||
|
endCharacterOffset = endCharacterOffset ? endLineOffset : characterOffset;
|
||||||
|
const endPosition = new vscode.Position(end.line + endLineOffset, end.character + endCharacterOffset);
|
||||||
|
return new vscode.Range(startPosition, endPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function positionAfter(positionA: Position, positionB: Position): boolean {
|
||||||
|
return positionA.line > positionB.line || (
|
||||||
|
positionA.line === positionB.line &&
|
||||||
|
positionA.character > positionB.character);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function positionEqual(positionA: Position, positionB: Position): boolean {
|
||||||
|
return positionA.line === positionB.line &&
|
||||||
|
positionA.character === positionB.character;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description positionA behind or equal to positionB
|
||||||
|
*/
|
||||||
|
function positionAfterEqual(positionA: Position, positionB: Position): boolean {
|
||||||
|
return positionAfter(positionA, positionB) ||
|
||||||
|
positionEqual(positionA, positionB);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description filter the symbol result item that exceed the scope
|
||||||
|
*/
|
||||||
|
function filterSymbolScope(position: vscode.Position, rawSymbols: RawSymbol[]): AllowNull<ModuleScope> {
|
||||||
|
if (!rawSymbols) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const parentModules = rawSymbols.filter(item =>
|
||||||
|
item.type === 'module' &&
|
||||||
|
positionAfterEqual(position, item.range.start) &&
|
||||||
|
positionAfterEqual(item.range.end, position)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (parentModules.length === 0) {
|
||||||
|
// TODO : macro
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentModule = parentModules[0];
|
||||||
|
const symbols = rawSymbols.filter(item =>
|
||||||
|
item !== parentModule &&
|
||||||
|
positionAfterEqual(item.range.start, parentModule.range.start) &&
|
||||||
|
positionAfterEqual(parentModule.range.end, item.range.end));
|
||||||
|
|
||||||
|
return {
|
||||||
|
module : parentModule,
|
||||||
|
symbols : symbols
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function isInComment(document: vscode.TextDocument, position: Position, comments: CommentResult[]): boolean {
|
||||||
|
if (!comments) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// remove the situation that <cursor> // comment
|
||||||
|
const lineText = document.lineAt(makeVscodePosition(position)).text;
|
||||||
|
const singleCommentIndex = lineText.indexOf('//');
|
||||||
|
if (singleCommentIndex !== -1) {
|
||||||
|
return position.character >= singleCommentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentLine = position.line + 1;
|
||||||
|
for (const comment of comments) {
|
||||||
|
const commentLine = comment.start.line;
|
||||||
|
if (commentLine > currentLine) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const startPosition = new vscode.Position(commentLine, 0);
|
||||||
|
const startOffset = document.offsetAt(startPosition);
|
||||||
|
const endPosition = document.positionAt(startOffset + comment.length);
|
||||||
|
|
||||||
|
const originalPosition: Position = {line: currentLine, character: position.character};
|
||||||
|
|
||||||
|
if (positionAfterEqual(originalPosition, startPosition) &&
|
||||||
|
positionAfterEqual(endPosition, originalPosition)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function matchInclude(document: vscode.TextDocument, position: vscode.Position, includes: Include[]) : AllowNull<MatchedSymbol> {
|
||||||
|
const selectFileRange = document.getWordRangeAtPosition(position, /[\._0-9A-Za-z]+/);
|
||||||
|
const selectFileName = document.getText(selectFileRange);
|
||||||
|
|
||||||
|
if (!includes) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (const include of includes) {
|
||||||
|
const range = include.range;
|
||||||
|
if (position.line + 1 === range.start.line && selectFileName === include.path) {
|
||||||
|
return {
|
||||||
|
name : include.path,
|
||||||
|
value: include.path,
|
||||||
|
range: range
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function matchDefine(position: vscode.Position, defines: Define[]) : AllowNull<MatchedSymbol> {
|
||||||
|
if (!defines) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const define of defines) {
|
||||||
|
const range = define.range;
|
||||||
|
if (positionAfterEqual(position, range.start) &&
|
||||||
|
positionAfterEqual(range.end, position)) {
|
||||||
|
return {
|
||||||
|
name : define.name,
|
||||||
|
value: define.replacement,
|
||||||
|
range: range
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function matchDefineMacro(position: vscode.Position, singleWord: string, defines: Define[]) : AllowNull<MatchedSymbol> {
|
||||||
|
if (!defines) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (singleWord[0] !== '`' || singleWord.length <= 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const targetMacro = singleWord.substring(1);
|
||||||
|
for (const define of defines) {
|
||||||
|
if (define.name === targetMacro) {
|
||||||
|
const range = define.range;
|
||||||
|
return {
|
||||||
|
name : define.name,
|
||||||
|
value : define.replacement,
|
||||||
|
range : range
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function matchInstance(singleWord: string, module: HdlModule): AllowNull<HdlInstance> {
|
||||||
|
for (const inst of module.getAllInstances()) {
|
||||||
|
if (singleWord === inst.type) {
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function filterInstanceByPosition(position: vscode.Position, symbols: RawSymbol[], module: HdlModule): AllowNull<HdlInstance> {
|
||||||
|
if (!symbols) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (const symbol of symbols) {
|
||||||
|
const inst = module.getInstance(symbol.name);
|
||||||
|
if (positionAfterEqual(position, symbol.range.start) &&
|
||||||
|
positionAfterEqual(symbol.range.end, position) &&
|
||||||
|
inst) {
|
||||||
|
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function getInstPortByPosition(inst: HdlInstance, position: vscode.Position, singleWord: string): Promise<AllowNull<HdlModulePort>> {
|
||||||
|
if (!inst.module || !inst.instports) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const instportRange = transformRange(inst.instports, -1, 0);
|
||||||
|
|
||||||
|
if (positionAfterEqual(position, instportRange.start) &&
|
||||||
|
positionAfterEqual(instportRange.end, position)) {
|
||||||
|
for (const port of inst.module.ports) {
|
||||||
|
if (port.name === singleWord) {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function getInstParamByPosition(inst: AllowNull<HdlInstance>, position: vscode.Position, singleWord: string): Promise<AllowNull<HdlModuleParam>> {
|
||||||
|
if (!inst || !inst.module || !inst.instparams) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const instParamRange = transformRange(inst.instparams, -1, 0);
|
||||||
|
|
||||||
|
if (positionAfterEqual(position, instParamRange.start) &&
|
||||||
|
positionAfterEqual(instParamRange.end, position)) {
|
||||||
|
for (const param of inst.module.params) {
|
||||||
|
if (param.name === singleWord) {
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function isPositionInput(lineText: string, character: number): boolean {
|
||||||
|
const alphaReg = /[_0-9A-Za-z]/;
|
||||||
|
for (let i = character; i >= 0; -- i) {
|
||||||
|
const ch = lineText[i];
|
||||||
|
if (alphaReg.test(ch)) {
|
||||||
|
continue;
|
||||||
|
} else if (ch === '.') {
|
||||||
|
if (i === 0) {
|
||||||
|
return true;
|
||||||
|
} else if (lineText[i - 1] === ' ') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function matchPorts(singleWord: string, module: HdlModule): AllowNull<HdlModulePort> {
|
||||||
|
if (!module || module.ports.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const targetPorts = module.ports.filter(port => port.name === singleWord);
|
||||||
|
if (targetPorts.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return targetPorts[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function matchParams(singleWord: string, module: HdlModule): AllowNull<HdlModuleParam> {
|
||||||
|
if (module.params.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetParams = module.params.filter(param => param.name === singleWord);
|
||||||
|
if (targetParams.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return targetParams[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function makePortDesc(port: HdlModulePort): string {
|
||||||
|
let portDesc: string = port.type;
|
||||||
|
if (port.width && port.width !== Unknown) {
|
||||||
|
portDesc += ' ' + port.width;
|
||||||
|
}
|
||||||
|
portDesc += ' ' + port.name;
|
||||||
|
return portDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function makeParamDesc(param: HdlModuleParam): string {
|
||||||
|
let paramDesc = 'parameter ' + param.name;
|
||||||
|
if (param.init && param.init !== Unknown) {
|
||||||
|
paramDesc += ' = ' + param.init;
|
||||||
|
}
|
||||||
|
return paramDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeNormalDesc(normal: RawSymbol): string {
|
||||||
|
const desc = normal.type + ' ' + normal.width + ' ' + normal.name;
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function matchNormalSymbol(singleWord: string, symbols: RawSymbol[]): AllowNull<RawSymbol> {
|
||||||
|
if (!symbols || Object.keys(symbols).length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (const symbol of symbols) {
|
||||||
|
if (singleWord === symbol.name) {
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function makeVlogHoverContent(content: vscode.MarkdownString, module: HdlModule) {
|
||||||
|
const portNum = module.ports.length;
|
||||||
|
const paramNum = module.params.length;
|
||||||
|
const instNum = module.getInstanceNum();
|
||||||
|
|
||||||
|
const moduleUri = vscode.Uri.file(module.path);
|
||||||
|
const thenableFileDocument = vscode.workspace.openTextDocument(moduleUri);
|
||||||
|
|
||||||
|
const portDesc = ' $(instance-param) ' + paramNum +
|
||||||
|
' $(instance-port) ' + portNum +
|
||||||
|
' $(instance-module)' + instNum;
|
||||||
|
|
||||||
|
|
||||||
|
content.appendMarkdown(portDesc);
|
||||||
|
content.appendText(' | ');
|
||||||
|
|
||||||
|
const count = {
|
||||||
|
input: 0,
|
||||||
|
output: 0,
|
||||||
|
inout: 0
|
||||||
|
};
|
||||||
|
for (const port of module.ports) {
|
||||||
|
count[port.type as keyof typeof count] += 1;
|
||||||
|
}
|
||||||
|
const ioDesc = ' $(instance-input) ' + count.input +
|
||||||
|
' $(instance-output) ' + count.output +
|
||||||
|
' $(instance-inout)' + count.inout;
|
||||||
|
content.appendMarkdown(ioDesc);
|
||||||
|
content.appendText('\n');
|
||||||
|
|
||||||
|
content.appendMarkdown('---');
|
||||||
|
|
||||||
|
// make document
|
||||||
|
const fileDocument = await thenableFileDocument;
|
||||||
|
const range = transformRange(module.range, -1, 0, 1);
|
||||||
|
const moduleDefinitionCode = fileDocument.getText(range);
|
||||||
|
content.appendCodeblock(moduleDefinitionCode, 'verilog');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function searchCommentAround(path: AbsPath, range: Range): Promise<string | null> {
|
||||||
|
const targetRange = transformRange(range, -1, 0);
|
||||||
|
const comment = await getSymbolComment(path, targetRange);
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
transformRange,
|
||||||
|
filterSymbolScope,
|
||||||
|
filterInstanceByPosition,
|
||||||
|
isPositionInput,
|
||||||
|
isInComment,
|
||||||
|
matchInclude,
|
||||||
|
matchDefine,
|
||||||
|
matchDefineMacro,
|
||||||
|
matchInstance,
|
||||||
|
matchPorts,
|
||||||
|
matchParams,
|
||||||
|
matchNormalSymbol,
|
||||||
|
makeVlogHoverContent,
|
||||||
|
positionAfterEqual,
|
||||||
|
getInstPortByPosition,
|
||||||
|
getInstParamByPosition,
|
||||||
|
makePortDesc,
|
||||||
|
makeParamDesc,
|
||||||
|
makeNormalDesc,
|
||||||
|
transferVlogNumber,
|
||||||
|
searchCommentAround,
|
||||||
|
};
|
130
src/function/lsp/util/keyword.ts
Normal file
130
src/function/lsp/util/keyword.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
|
|
||||||
|
class Keywords {
|
||||||
|
keywords: Set<string>;
|
||||||
|
keywordItems: vscode.CompletionItem[];
|
||||||
|
compilerKeywords: string[]; // start with `
|
||||||
|
systemKeywords: string[]; // start with $
|
||||||
|
constructor(keywords: string[], compilerKeywords: string[], systemKeywords: string[]) {
|
||||||
|
this.keywords = new Set(keywords);
|
||||||
|
const keywordItems = [];
|
||||||
|
for (const keyword of keywords) {
|
||||||
|
const clItem = new vscode.CompletionItem(keyword, vscode.CompletionItemKind.Keyword);
|
||||||
|
clItem.detail = "keyword";
|
||||||
|
keywordItems.push(clItem);
|
||||||
|
}
|
||||||
|
this.keywordItems = keywordItems;
|
||||||
|
this.compilerKeywords = compilerKeywords;
|
||||||
|
this.systemKeywords = systemKeywords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public keys(): Set<string> {
|
||||||
|
return this.keywords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public isKeyword(word: string): boolean {
|
||||||
|
return this.keywords.has(word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const vlogKeyword = new Keywords([
|
||||||
|
"above", "disable", "idt", "notif1", "supply0", "abs", "discipline", "idtmod",
|
||||||
|
"or", "supply1", "absdelay", "driver_update", "if", "output", "table", "ac_stim",
|
||||||
|
"edge", "ifnone", "parameter", "tan", "acos", "else", "inf", "pmos", "tanh",
|
||||||
|
"acosh", "end", "initial", "posedge", "task", "always", "endcase", "initial_step",
|
||||||
|
"potential", "time", "analog", "endconnectrules", "inout", "pow", "timer", "analysis",
|
||||||
|
"enddiscipline", "input", "primitive", "tran", "and", "endfunction", "integer",
|
||||||
|
"pull0", "tranif0", "asin", "endmodule", "join", "pull1", "tranif1", "asinh",
|
||||||
|
"endnature", "laplace_nd", "pulldown", "transition", "assign", "endprimitive",
|
||||||
|
"laplace_np", "pullup", "tri", "atan", "endspecify", "laplace_zd", "rcmos", "tri0",
|
||||||
|
"atan2", "endtable", "laplace_zp", "real", "tri1", "atanh", "endtask", "large",
|
||||||
|
"realtime", "triand", "begin", "event", "last_crossing", "reg", "trior", "branch",
|
||||||
|
"exclude", "limexp", "release", "trireg", "buf", "exp", "ln", "repeat", "vectored",
|
||||||
|
"bufif0", "final_step", "log", "rnmos", "wait", "bufif1", "flicker_noise", "macromodule",
|
||||||
|
"rpmos", "wand", "case", "flow", "max", "rtran", "weak0", "casex", "for", "medium",
|
||||||
|
"rtranif0", "weak1", "casez", "force", "min", "rtranif1", "while", "ceil", "forever",
|
||||||
|
"module", "scalared", "white_noise", "cmos", "fork", "nand", "sin", "wire",
|
||||||
|
"connectrules", "from", "nature", "sinh", "wor", "cos", "function", "negedge",
|
||||||
|
"slew", "wreal", "cosh", "generate", "net_resolution", "small", "xnor", "cross",
|
||||||
|
"genvar", "nmos", "specify", "xor", "ddt", "ground", "noise_table", "specparam",
|
||||||
|
"zi_nd", "deassign", "highz0", "nor", "sqrt", "zi_np", "default", "highz1",
|
||||||
|
"not", "strong0", "zi_zd", "defparam", "hypot", "notif0", "strong1", "zi_zp",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"begin_keywords", "celldefine", "default_nettype", "define", "else", "elsif",
|
||||||
|
"end_keywords", "endcelldefine", "endif", "ifdef", "ifndef", "include", "line",
|
||||||
|
"nounconnected_drive", "pragma", "resetall", "timescale", "unconnected_drive", "undef"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'acos', 'sqrt', 'ftell', 'fdisplay', 'fclose', 'timeformat', 'fseek', 'asinh', 'fdisplayh',
|
||||||
|
'fmonitorb', 'dist_erlang', 'writeb', 'fwrite', 'swriteb', 'printtimescale', 'displayb', 'atan',
|
||||||
|
'sscanf', 'exp', 'nand', 'fdisplayo', 'sdf_annotate', 'stime', 'sin', 'dist_chi_square', 'strobeh',
|
||||||
|
'array', 'swriteo', 'and', 'dist_normal', 'readmemb', 'strobeb', 'realtobits', 'or', 'dist_exponential',
|
||||||
|
'plusargs', 'hypot', 'swrite', 'writeh', 'plane', 'fstrobeb', 'time', 'fread', 'fstrobe', 'rewind', 'async',
|
||||||
|
'sync', 'bitstoreal', 'readmemh', 'fwriteo', 'value', 'tanh', 'rtoi', 'fgetc', 'realtime', 'atan2', 'acosh',
|
||||||
|
'displayh', 'log10', 'clog2', 'fstrobeo', 'pow', 'fwriteb', 'fwriteh', 'nor', 'fdisplayb', 'monitoroff', 'fgets',
|
||||||
|
'q_add', 'atanh', 'monitor', 'monitorh', 'cos', 'ln', 'q_initialize', 'unsigned', 'swriteh', 'asin', 'monitoron',
|
||||||
|
'monitoro', 'display', 'tan', 'fscanf', 'dist_uniform', 'test', 'q_exam', 'itor', 'random', 'fstrobeh', 'strobe',
|
||||||
|
'displayo', 'monitorb', 'ungetc', 'feof', 'stop', 'ferror', 'finish', 'fmonitor', 'fmonitorh', 'cosh', 'writeo', 'sinh',
|
||||||
|
'dist_poisson', 'write', 'fopen', 'fmonitoro', 'fflush', 'ceil', 'strobeo', 'dist_t', 'q_full', 'signed', 'sformat',
|
||||||
|
'q_remove', 'floor',
|
||||||
|
'dumpfile', 'dumpvars', 'dumpoff', 'dumpon', 'dumpall', 'dumplimit', 'dumpflush',
|
||||||
|
'dumpports', 'dumpportsoff', 'dumpportson', 'dumpportsall', 'dumpportslimit', 'dumpportsflush'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO : do vhdl and sv version
|
||||||
|
const vhdlKeyword = new Keywords([], [], []);
|
||||||
|
|
||||||
|
const systemverilogKeyword = new Keywords([
|
||||||
|
"above", "disable", "idt", "notif1", "supply0", "abs", "discipline", "idtmod",
|
||||||
|
"or", "supply1", "absdelay", "driver_update", "if", "output", "table", "ac_stim",
|
||||||
|
"edge", "ifnone", "parameter", "tan", "acos", "else", "inf", "pmos", "tanh",
|
||||||
|
"acosh", "end", "initial", "posedge", "task", "always", "endcase", "initial_step",
|
||||||
|
"potential", "time", "analog", "endconnectrules", "inout", "pow", "timer", "analysis",
|
||||||
|
"enddiscipline", "input", "primitive", "tran", "and", "endfunction", "integer",
|
||||||
|
"pull0", "tranif0", "asin", "endmodule", "join", "pull1", "tranif1", "asinh",
|
||||||
|
"endnature", "laplace_nd", "pulldown", "transition", "assign", "endprimitive",
|
||||||
|
"laplace_np", "pullup", "tri", "atan", "endspecify", "laplace_zd", "rcmos", "tri0",
|
||||||
|
"atan2", "endtable", "laplace_zp", "real", "tri1", "atanh", "endtask", "large",
|
||||||
|
"realtime", "triand", "begin", "event", "last_crossing", "reg", "trior", "branch",
|
||||||
|
"exclude", "limexp", "release", "trireg", "buf", "exp", "ln", "repeat", "vectored",
|
||||||
|
"bufif0", "final_step", "log", "rnmos", "wait", "bufif1", "flicker_noise", "macromodule",
|
||||||
|
"rpmos", "wand", "case", "flow", "max", "rtran", "weak0", "casex", "for", "medium",
|
||||||
|
"rtranif0", "weak1", "casez", "force", "min", "rtranif1", "while", "ceil", "forever",
|
||||||
|
"module", "scalared", "white_noise", "cmos", "fork", "nand", "sin", "wire",
|
||||||
|
"connectrules", "from", "nature", "sinh", "wor", "cos", "function", "negedge",
|
||||||
|
"slew", "wreal", "cosh", "generate", "net_resolution", "small", "xnor", "cross",
|
||||||
|
"genvar", "nmos", "specify", "xor", "ddt", "ground", "noise_table", "specparam",
|
||||||
|
"zi_nd", "deassign", "highz0", "nor", "sqrt", "zi_np", "default", "highz1",
|
||||||
|
"not", "strong0", "zi_zd", "defparam", "hypot", "notif0", "strong1", "zi_zp"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"begin_keywords", "celldefine", "default_nettype", "define", "else", "elsif",
|
||||||
|
"end_keywords", "endcelldefine", "endif", "ifdef", "ifndef", "include", "line",
|
||||||
|
"nounconnected_drive", "pragma", "resetall", "timescale", "unconnected_drive", "undef"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'acos', 'sqrt', 'ftell', 'fdisplay', 'fclose', 'timeformat', 'fseek', 'asinh', 'fdisplayh',
|
||||||
|
'fmonitorb', 'dist_erlang', 'writeb', 'fwrite', 'swriteb', 'printtimescale', 'displayb', 'atan',
|
||||||
|
'sscanf', 'exp', 'nand', 'fdisplayo', 'sdf_annotate', 'stime', 'sin', 'dist_chi_square', 'strobeh',
|
||||||
|
'array', 'swriteo', 'and', 'dist_normal', 'readmemb', 'strobeb', 'realtobits', 'or', 'dist_exponential',
|
||||||
|
'plusargs', 'hypot', 'swrite', 'writeh', 'plane', 'fstrobeb', 'time', 'fread', 'fstrobe', 'rewind', 'async',
|
||||||
|
'sync', 'bitstoreal', 'readmemh', 'fwriteo', 'value', 'tanh', 'rtoi', 'fgetc', 'realtime', 'atan2', 'acosh',
|
||||||
|
'displayh', 'log10', 'clog2', 'fstrobeo', 'pow', 'fwriteb', 'fwriteh', 'nor', 'fdisplayb', 'monitoroff', 'fgets',
|
||||||
|
'q_add', 'atanh', 'monitor', 'monitorh', 'cos', 'ln', 'q_initialize', 'unsigned', 'swriteh', 'asin', 'monitoron',
|
||||||
|
'monitoro', 'display', 'tan', 'fscanf', 'dist_uniform', 'test', 'q_exam', 'itor', 'random', 'fstrobeh', 'strobe',
|
||||||
|
'displayo', 'monitorb', 'ungetc', 'feof', 'stop', 'ferror', 'finish', 'fmonitor', 'fmonitorh', 'cosh', 'writeo', 'sinh',
|
||||||
|
'dist_poisson', 'write', 'fopen', 'fmonitoro', 'fflush', 'ceil', 'strobeo', 'dist_t', 'q_full', 'signed', 'sformat',
|
||||||
|
'q_remove', 'floor'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
vlogKeyword,
|
||||||
|
vhdlKeyword,
|
||||||
|
systemverilogKeyword
|
||||||
|
};
|
@ -8,6 +8,8 @@ import * as Lang from './lang';
|
|||||||
type AbsPath = string;
|
type AbsPath = string;
|
||||||
type RelPath = string;
|
type RelPath = string;
|
||||||
|
|
||||||
|
type AllowNull<T> = T | null;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
opeParam,
|
opeParam,
|
||||||
OpeParamDefaults,
|
OpeParamDefaults,
|
||||||
@ -19,5 +21,6 @@ export {
|
|||||||
RelPath,
|
RelPath,
|
||||||
MainOutput,
|
MainOutput,
|
||||||
YosysOutput,
|
YosysOutput,
|
||||||
ReportType
|
ReportType,
|
||||||
|
AllowNull
|
||||||
};
|
};
|
@ -1,4 +1,5 @@
|
|||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
import { AbsPath, RelPath } from '../global';
|
import { AbsPath, RelPath } from '../global';
|
||||||
|
|
||||||
@ -10,6 +11,10 @@ interface Position {
|
|||||||
character: number
|
character: number
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function makeVscodePosition(position: Position): vscode.Position {
|
||||||
|
return new vscode.Position(position.line, position.character);
|
||||||
|
}
|
||||||
|
|
||||||
interface Range {
|
interface Range {
|
||||||
start: Position
|
start: Position
|
||||||
end: Position
|
end: Position
|
||||||
@ -32,11 +37,45 @@ enum HdlFileType {
|
|||||||
RemoteLib = 'remote_lib'
|
RemoteLib = 'remote_lib'
|
||||||
};
|
};
|
||||||
enum InstModPathStatus {Current, Include, Others, Unknown};
|
enum InstModPathStatus {Current, Include, Others, Unknown};
|
||||||
enum SymbolType {
|
// enum SymbolType {
|
||||||
Module = 'module',
|
// Module = 'module',
|
||||||
Input = 'input',
|
// Input = 'input',
|
||||||
Output = 'output'
|
// Output = 'output',
|
||||||
};
|
// Inout = 'inout',
|
||||||
|
// Program = 'program',
|
||||||
|
// Package = 'package',
|
||||||
|
// Import = 'import',
|
||||||
|
// Always = 'always',
|
||||||
|
// Processe = 'processe',
|
||||||
|
// Task = 'task',
|
||||||
|
// Function = 'function',
|
||||||
|
// Assert = 'assert',
|
||||||
|
// Event = 'event',
|
||||||
|
// Instance = 'instance',
|
||||||
|
// Time = 'time',
|
||||||
|
// Define = 'define',
|
||||||
|
// Typedef = 'typedef',
|
||||||
|
// Generate = 'generate',
|
||||||
|
// Enum = 'enum',
|
||||||
|
// Modport = 'modport',
|
||||||
|
// Property = 'property',
|
||||||
|
// Interface = 'interface',
|
||||||
|
// Buffer = 'buffer',
|
||||||
|
// Localparam = 'localparam',
|
||||||
|
// Parameter = 'parameter',
|
||||||
|
// Integer = 'integer',
|
||||||
|
// Char = 'char',
|
||||||
|
// Float = 'float',
|
||||||
|
// Int = 'int',
|
||||||
|
// String = 'string',
|
||||||
|
// Struct = 'struct',
|
||||||
|
// Class = 'class',
|
||||||
|
// Logic = 'logic',
|
||||||
|
// Wire = 'wire',
|
||||||
|
// Reg = 'reg',
|
||||||
|
// Net = 'net',
|
||||||
|
// Bit = 'bit'
|
||||||
|
// };
|
||||||
|
|
||||||
interface Error {
|
interface Error {
|
||||||
severity: number
|
severity: number
|
||||||
@ -45,12 +84,30 @@ interface Error {
|
|||||||
range: Range
|
range: Range
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Define {
|
interface DefineParam {
|
||||||
// `define A out
|
name: string,
|
||||||
// name is "A", value is "out"
|
|
||||||
name: string
|
|
||||||
value: string
|
value: string
|
||||||
range: Position
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `define A out
|
||||||
|
* name is "A", replacement is "out"
|
||||||
|
* `define max(a, b=1) a*b
|
||||||
|
* name is "max", replacement is "a*b", params is
|
||||||
|
* {
|
||||||
|
"name": "a",
|
||||||
|
"value": "Unknown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "b",
|
||||||
|
"value": "1"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
interface Define {
|
||||||
|
name: string
|
||||||
|
replacement: string
|
||||||
|
range: Range
|
||||||
|
params: DefineParam[],
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Include {
|
interface Include {
|
||||||
@ -105,8 +162,9 @@ interface RawHdlModule {
|
|||||||
|
|
||||||
interface RawSymbol {
|
interface RawSymbol {
|
||||||
name: string
|
name: string
|
||||||
type: SymbolType
|
type: string
|
||||||
range: Range
|
range: Range
|
||||||
|
width?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
interface InstModPathSearchResult {
|
interface InstModPathSearchResult {
|
||||||
@ -120,6 +178,12 @@ interface HdlDependence {
|
|||||||
others: AbsPath[]
|
others: AbsPath[]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface CommentResult {
|
||||||
|
start: { line : number }
|
||||||
|
length: number
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Position,
|
Position,
|
||||||
Range,
|
Range,
|
||||||
@ -138,5 +202,7 @@ export {
|
|||||||
RawHdlModule,
|
RawHdlModule,
|
||||||
InstModPathSearchResult,
|
InstModPathSearchResult,
|
||||||
HdlDependence,
|
HdlDependence,
|
||||||
RawSymbol
|
RawSymbol,
|
||||||
|
CommentResult,
|
||||||
|
makeVscodePosition
|
||||||
};
|
};
|
@ -72,10 +72,6 @@ class HdlParam {
|
|||||||
this.modules.add(hdlModule);
|
this.modules.add(hdlModule);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* add module to global top modules
|
|
||||||
* @param hdlModule
|
|
||||||
*/
|
|
||||||
public addTopModule(hdlModule: HdlModule) {
|
public addTopModule(hdlModule: HdlModule) {
|
||||||
this.topModules.add(hdlModule);
|
this.topModules.add(hdlModule);
|
||||||
}
|
}
|
||||||
@ -204,13 +200,19 @@ class HdlParam {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async initHdlFiles(hdlFiles: AbsPath[] | Generator<AbsPath>) {
|
public async initHdlFiles(hdlFiles: AbsPath[] | Generator<AbsPath>) {
|
||||||
|
const pools: Promise<void>[] = [];
|
||||||
for (const path of hdlFiles) {
|
for (const path of hdlFiles) {
|
||||||
this.doHdlFast(path);
|
const p = this.doHdlFast(path);
|
||||||
|
pools.push(p);
|
||||||
|
}
|
||||||
|
for (const p of pools) {
|
||||||
|
await p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async initialize(hdlFiles: AbsPath[] | Generator<AbsPath>) {
|
public async initialize(hdlFiles: AbsPath[] | Generator<AbsPath>) {
|
||||||
await this.initHdlFiles(hdlFiles);
|
await this.initHdlFiles(hdlFiles);
|
||||||
|
|
||||||
for (const hdlFile of this.getAllHdlFiles()) {
|
for (const hdlFile of this.getAllHdlFiles()) {
|
||||||
hdlFile.makeInstance();
|
hdlFile.makeInstance();
|
||||||
}
|
}
|
||||||
@ -296,6 +298,7 @@ class HdlInstance {
|
|||||||
|
|
||||||
if (instModPath) {
|
if (instModPath) {
|
||||||
this.module = hdlParam.getHdlModule(instModPath, instModName);
|
this.module = hdlParam.getHdlModule(instModPath, instModName);
|
||||||
|
|
||||||
// add refer for module
|
// add refer for module
|
||||||
this.module?.addGlobalReferedInstance(this);
|
this.module?.addGlobalReferedInstance(this);
|
||||||
// if module and parent module share the same source (e.g both in src folder)
|
// if module and parent module share the same source (e.g both in src folder)
|
||||||
@ -348,8 +351,19 @@ class HdlModule {
|
|||||||
this.params = params;
|
this.params = params;
|
||||||
this.ports = ports;
|
this.ports = ports;
|
||||||
|
|
||||||
|
if (!this.params) {
|
||||||
|
this.params = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.ports) {
|
||||||
|
this.ports = [];
|
||||||
|
}
|
||||||
|
|
||||||
// make instance
|
// make instance
|
||||||
this.rawInstances = instances;
|
this.rawInstances = instances;
|
||||||
|
if (!this.rawInstances) {
|
||||||
|
this.rawInstances = [];
|
||||||
|
}
|
||||||
this.nameToInstances = new Map<string, HdlInstance>();
|
this.nameToInstances = new Map<string, HdlInstance>();
|
||||||
|
|
||||||
// add in hdlParam data structure
|
// add in hdlParam data structure
|
||||||
@ -397,6 +411,7 @@ class HdlModule {
|
|||||||
|
|
||||||
public createHdlInstance(rawHdlInstance: common.RawHdlInstance): HdlInstance {
|
public createHdlInstance(rawHdlInstance: common.RawHdlInstance): HdlInstance {
|
||||||
const instModName = rawHdlInstance.type;
|
const instModName = rawHdlInstance.type;
|
||||||
|
|
||||||
const searchResult = this.searchInstModPath(instModName);
|
const searchResult = this.searchInstModPath(instModName);
|
||||||
const hdlInstance = new HdlInstance(rawHdlInstance.name,
|
const hdlInstance = new HdlInstance(rawHdlInstance.name,
|
||||||
rawHdlInstance.type,
|
rawHdlInstance.type,
|
||||||
@ -417,6 +432,7 @@ class HdlModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public makeNameToInstances() {
|
public makeNameToInstances() {
|
||||||
|
|
||||||
if (this.rawInstances) {
|
if (this.rawInstances) {
|
||||||
this.nameToInstances.clear();
|
this.nameToInstances.clear();
|
||||||
for (const inst of this.rawInstances) {
|
for (const inst of this.rawInstances) {
|
||||||
@ -508,6 +524,7 @@ class HdlModule {
|
|||||||
public addGlobalReferedInstance(inst: HdlInstance) {
|
public addGlobalReferedInstance(inst: HdlInstance) {
|
||||||
const globalRefers = this.globalRefers;
|
const globalRefers = this.globalRefers;
|
||||||
globalRefers.add(inst);
|
globalRefers.add(inst);
|
||||||
|
// it is refered in global scope, so delete this from top module
|
||||||
if (globalRefers.size > 0) {
|
if (globalRefers.size > 0) {
|
||||||
hdlParam.deleteTopModule(this);
|
hdlParam.deleteTopModule(this);
|
||||||
}
|
}
|
||||||
@ -524,6 +541,7 @@ class HdlModule {
|
|||||||
public addLocalReferedInstance(inst: HdlInstance) {
|
public addLocalReferedInstance(inst: HdlInstance) {
|
||||||
const localRefers = this.localRefers;
|
const localRefers = this.localRefers;
|
||||||
localRefers.add(inst);
|
localRefers.add(inst);
|
||||||
|
// it is refered in local scope, so delete this from top module
|
||||||
if (localRefers.size > 0) {
|
if (localRefers.size > 0) {
|
||||||
hdlParam.deleteTopModuleToSource(this);
|
hdlParam.deleteTopModuleToSource(this);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ namespace HdlSymbol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
HdlSymbol
|
HdlSymbol,
|
||||||
};
|
};
|
@ -49,7 +49,7 @@ class PrjManage {
|
|||||||
* init opeParam
|
* init opeParam
|
||||||
* @param context
|
* @param context
|
||||||
*/
|
*/
|
||||||
public initOpeParam(context: vscode.ExtensionContext) {
|
public async initOpeParam(context: vscode.ExtensionContext) {
|
||||||
const os = process.platform;
|
const os = process.platform;
|
||||||
const extensionPath = hdlPath.toSlash(context.extensionPath);
|
const extensionPath = hdlPath.toSlash(context.extensionPath);
|
||||||
const workspacePath = this.getWorkspacePath();
|
const workspacePath = this.getWorkspacePath();
|
||||||
@ -71,6 +71,15 @@ class PrjManage {
|
|||||||
if (fs.existsSync(propertyJsonPath)) {
|
if (fs.existsSync(propertyJsonPath)) {
|
||||||
const rawPrjInfo = hdlFile.readJSON(propertyJsonPath) as RawPrjInfo;
|
const rawPrjInfo = hdlFile.readJSON(propertyJsonPath) as RawPrjInfo;
|
||||||
opeParam.mergePrjInfo(rawPrjInfo);
|
opeParam.mergePrjInfo(rawPrjInfo);
|
||||||
|
} else {
|
||||||
|
const createProperty = await vscode.window.showInformationMessage(
|
||||||
|
"property.json is not detected, do you want to create one ?",
|
||||||
|
{ title: 'Yes', value: true },
|
||||||
|
{ title: 'No', value: false }
|
||||||
|
);
|
||||||
|
if (createProperty?.value) {
|
||||||
|
vscode.commands.executeCommand('digital-ide.property-json.generate');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +115,7 @@ class PrjManage {
|
|||||||
console.time('launch');
|
console.time('launch');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initOpeParam(context);
|
await this.initOpeParam(context);
|
||||||
MainOutput.report('finish initialise opeParam', ReportType.Info);
|
MainOutput.report('finish initialise opeParam', ReportType.Info);
|
||||||
|
|
||||||
const hdlFiles = this.getPrjHardwareFiles();
|
const hdlFiles = this.getPrjHardwareFiles();
|
||||||
@ -121,7 +130,6 @@ class PrjManage {
|
|||||||
MainOutput.report('create pl and ps', ReportType.Info);
|
MainOutput.report('create pl and ps', ReportType.Info);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (countTimeCost) {
|
if (countTimeCost) {
|
||||||
console.timeLog('launch');
|
console.timeLog('launch');
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
module dependence_1 (
|
module dependence_1 (
|
||||||
|
// this is a test
|
||||||
input a, b, c,
|
input a, b, c,
|
||||||
output Q
|
// a test
|
||||||
|
output Result // balabalabala for result
|
||||||
);
|
);
|
||||||
|
|
||||||
// a & b | ((b & c) & (b | c))
|
// a & b | ((b & c) & (b | c))
|
||||||
@ -10,6 +12,6 @@ module dependence_1 (
|
|||||||
// Simplify A + A = A AB + BC
|
// Simplify A + A = A AB + BC
|
||||||
// Factor B(A+C)
|
// Factor B(A+C)
|
||||||
|
|
||||||
assign Q = a & (b | c);
|
assign Result = a & (b | c);
|
||||||
|
|
||||||
endmodule
|
endmodule
|
@ -3,14 +3,17 @@
|
|||||||
* current file -> macro include -> whole project
|
* current file -> macro include -> whole project
|
||||||
* expect dependence_1 from child_1.v (macro include)
|
* expect dependence_1 from child_1.v (macro include)
|
||||||
* expect dependence_2 from child_2.v (whole project)
|
* expect dependence_2 from child_2.v (whole project)
|
||||||
* cannot find dependence_3
|
* cannot find dependence_3 `main
|
||||||
*/
|
*/
|
||||||
|
|
||||||
`include "child_1.v"
|
`include "child_1.v"
|
||||||
|
`include "child_2.v"
|
||||||
`define main out
|
`define main out
|
||||||
|
|
||||||
module Main (
|
module Main (
|
||||||
|
// Main input
|
||||||
input a, b, c,
|
input a, b, c,
|
||||||
|
// Main output
|
||||||
output Qus, Qs, `main
|
output Qus, Qs, `main
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -18,7 +21,7 @@ dependence_1 u_dependence_1(
|
|||||||
.a(a),
|
.a(a),
|
||||||
.b(b),
|
.b(b),
|
||||||
.c(c),
|
.c(c),
|
||||||
.Q(Qus)
|
.Result(Qus)
|
||||||
);
|
);
|
||||||
|
|
||||||
dependence_2 u_dependence_2(
|
dependence_2 u_dependence_2(
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
* CN: 如果使用`include "head_1.v" 则模块 dependence_1 使用的应该是 head_1.v 文件中的,
|
|
||||||
* 而不会调用child_1.v中的 dependence_1 同名模块。
|
|
||||||
* EN:
|
|
||||||
*/
|
|
||||||
|
|
||||||
`include "child_1.v"
|
|
||||||
`define main_o out
|
|
||||||
module Main(
|
|
||||||
input a, b, c,
|
|
||||||
output Qus, Qs, `main_o
|
|
||||||
);
|
|
||||||
|
|
||||||
dependence_1 dependence_1(
|
|
||||||
.a(a),
|
|
||||||
.b(b),
|
|
||||||
.c(c),
|
|
||||||
.Q(Qus)
|
|
||||||
);
|
|
||||||
|
|
||||||
dependence_2 dependence_2(
|
|
||||||
.a(a),
|
|
||||||
.b(b),
|
|
||||||
.c(c),
|
|
||||||
.Q(Qs)
|
|
||||||
);
|
|
||||||
|
|
||||||
endmodule
|
|
@ -6,6 +6,49 @@
|
|||||||
"keyEquivalent": "^~V",
|
"keyEquivalent": "^~V",
|
||||||
"name": "Verilog",
|
"name": "Verilog",
|
||||||
"patterns": [
|
"patterns": [
|
||||||
|
{
|
||||||
|
"begin": "\\s*(wire|reg)\\s+\\b([a-zA-Z_][a-zA-Z0-9_]*)\\b",
|
||||||
|
"beginCaptures": {
|
||||||
|
"1": {
|
||||||
|
"name": "keyword.control.verilog"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"name": "variable.other.constant.declaration.verilog"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"end": "(;)",
|
||||||
|
"endCaptures": {
|
||||||
|
"1": {
|
||||||
|
"name": "source.verilog"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"begin": "\\s*(wire|reg)\\s+\\[(.*?)(:)(.*?)\\]\\s+\\b([a-zA-Z_][a-zA-Z0-9_]*)\\b",
|
||||||
|
"beginCaptures": {
|
||||||
|
"1": {
|
||||||
|
"name": "keyword.control.verilog"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"name": "constant.numeric.width.verilog"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"name": "entity.name.function.width.spliter.verilog"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"name": "constant.numeric.width.verilog"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"name": "variable.other.constant.declaration.verilog"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"end": "(;)",
|
||||||
|
"endCaptures": {
|
||||||
|
"1": {
|
||||||
|
"name": "source.verilog"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"begin": "\\s*\\b(function|task)\\b(\\s+automatic)?",
|
"begin": "\\s*\\b(function|task)\\b(\\s+automatic)?",
|
||||||
"beginCaptures": {
|
"beginCaptures": {
|
||||||
@ -145,10 +188,10 @@
|
|||||||
"name": "support.class"
|
"name": "support.class"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"end": ";",
|
"end": "(;)",
|
||||||
"endCaptures": {
|
"endCaptures": {
|
||||||
"1": {
|
"1": {
|
||||||
"name": "entity.name.function.verilog"
|
"name": "source.verilog"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"patterns": [
|
"patterns": [
|
||||||
@ -166,7 +209,7 @@
|
|||||||
"include": "#ifmodport"
|
"include": "#ifmodport"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "variable.module.verilog"
|
"name": "variable.other.constant.module.verilog"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"captures": {
|
"captures": {
|
||||||
@ -637,10 +680,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"match": "\\b([a-zA-Z_][a-zA-Z0-9_]*)\\b(?=\\s*(\\(|$))",
|
"match": "\\b([a-zA-Z_][a-zA-Z0-9_]*)\\b(?=\\s*(\\(|$))",
|
||||||
"name": "support.class"
|
"name": "entity.name.function.module.verilog"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "meta.module.inst.param.verilog"
|
"name": "variable.other.constant.module.inst.param.verilog"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"begin": "\\b([a-zA-Z_][a-zA-Z0-9_]*)\\s+(?!intersect|and|or|throughout|within)([a-zA-Z_][a-zA-Z0-9_]*)\\s*(\\[(\\d+)(\\:(\\d+))?\\])?\\s*(\\(|$)",
|
"begin": "\\b([a-zA-Z_][a-zA-Z0-9_]*)\\s+(?!intersect|and|or|throughout|within)([a-zA-Z_][a-zA-Z0-9_]*)\\s*(\\[(\\d+)(\\:(\\d+))?\\])?\\s*(\\(|$)",
|
||||||
@ -649,7 +692,7 @@
|
|||||||
"name": "support.class"
|
"name": "support.class"
|
||||||
},
|
},
|
||||||
"2": {
|
"2": {
|
||||||
"name": "entity.name.module.verilog"
|
"name": "entity.name.function.module.verilog"
|
||||||
},
|
},
|
||||||
"4": {
|
"4": {
|
||||||
"name": "constant.numeric.verilog"
|
"name": "constant.numeric.verilog"
|
||||||
@ -676,7 +719,7 @@
|
|||||||
"include": "#constants"
|
"include": "#constants"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "variable.module.inst.verilog"
|
"name": "variable.other.constant.module.inst.verilog"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "meta.struct.assign.verilog",
|
"name": "meta.struct.assign.verilog",
|
||||||
@ -1047,7 +1090,7 @@
|
|||||||
"match": "\\.([a-zA-Z_][a-zA-Z0-9_]*)\\s*",
|
"match": "\\.([a-zA-Z_][a-zA-Z0-9_]*)\\s*",
|
||||||
"captures": {
|
"captures": {
|
||||||
"1": {
|
"1": {
|
||||||
"name": "keyword.inst.port.verilog"
|
"name": "variable.inst.port.verilog"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user