From b16f9bf104602fc713f4b10391202bb633b79d76 Mon Sep 17 00:00:00 2001 From: Kirigaya <1193466151@qq.com> Date: Sat, 22 Apr 2023 22:17:18 +0800 Subject: [PATCH] start lsp --- resources/hdlParser/index.d.ts | 5 +- resources/hdlParser/index.js | 56 +++------ src/function/lsp/docSymbol/index.ts | 0 src/function/lsp/docSymbol/vlog.ts | 187 ++++++++++++++++++++++++++++ src/hdlParser/core.ts | 34 ++--- src/hdlParser/index.ts | 4 +- src/manager/PL/index.ts | 57 ++++----- src/manager/PL/xilinx.ts | 6 +- src/manager/index.ts | 23 +++- 9 files changed, 272 insertions(+), 100 deletions(-) create mode 100644 src/function/lsp/docSymbol/index.ts create mode 100644 src/function/lsp/docSymbol/vlog.ts diff --git a/resources/hdlParser/index.d.ts b/resources/hdlParser/index.d.ts index bb61d42..7410836 100644 --- a/resources/hdlParser/index.d.ts +++ b/resources/hdlParser/index.d.ts @@ -6,10 +6,7 @@ type RelPath = string; type Path = AbsPath | RelPath; interface Fast { - content: { - error : string[] - modules: RawHdlModule[] - } + content: RawHdlModule[] languageId: HdlLangID macro: Macro } diff --git a/resources/hdlParser/index.js b/resources/hdlParser/index.js index 3d4bf56..cf211d5 100644 --- a/resources/hdlParser/index.js +++ b/resources/hdlParser/index.js @@ -18,62 +18,40 @@ const _hdlParser = { } }; -async function vlogFast(path) { - if (!fs.existsSync(path)) { - return undefined; - } - const wasmModule = await _hdlParser.acquire(); - const source = fs.readFileSync(path, 'utf-8') + '\n'; - wasmModule.FS.writeFile(_hdlParser.tempPath, source, { encoding: 'utf8' }); - const res = wasmModule.ccall('vlog_fast', 'string', ['string'], [_hdlParser.tempPath]); - try { - return JSON.parse(res); - } catch (err) { - console.log(res); - fs.writeFileSync('./draft.json', res); - console.log('error happen when parse ' + path); - console.log(err); - exit(-1); - } -} -async function vlogAll(path) { - if (!fs.existsSync(path)) { - return undefined; - } +async function callParser(path, func) { const wasmModule = await _hdlParser.acquire(); + const file = _hdlParser.tempPath; + const fileLength = file.length; const source = fs.readFileSync(path, 'utf-8') + '\n'; wasmModule.FS.writeFile(_hdlParser.tempPath, source, { encoding: 'utf8' }); - const res = wasmModule.ccall('vlog_all', 'string', ['string'], [_hdlParser.tempPath]); + const res = wasmModule.ccall('call_parser', 'string', ['string', 'int', 'int'], [file, fileLength, func]); return JSON.parse(res); } + async function vhdlFast(path) { - if (!fs.existsSync(path)) { - return undefined; - } - return {}; + return await callParser(path, 1); } async function vhdlAll(path) { - if (!fs.existsSync(path)) { - return undefined; - } - return {}; + return await callParser(path, 2); } async function svFast(path) { - if (!fs.existsSync(path)) { - return undefined; - } - return {}; + return await callParser(path, 3); } async function svAll(path) { - if (!fs.existsSync(path)) { - return undefined; - } - return {}; + return await callParser(path, 4); +} + +async function vlogFast(path) { + return await callParser(path, 5); +} + +async function vlogAll(path) { + return await callParser(path, 6); } module.exports = { diff --git a/src/function/lsp/docSymbol/index.ts b/src/function/lsp/docSymbol/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/function/lsp/docSymbol/vlog.ts b/src/function/lsp/docSymbol/vlog.ts new file mode 100644 index 0000000..2c176d2 --- /dev/null +++ b/src/function/lsp/docSymbol/vlog.ts @@ -0,0 +1,187 @@ +import * as vscode from 'vscode'; + +import { HdlSymbol } from '../../../hdlParser'; + +class VlogDocSymbolProvider implements vscode.DocumentSymbolProvider { + + public provideDocumentSymbols(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.ProviderResult { + const code = document.getText(); + const symbolResult = HdlSymbol.all(code); + const symbols = symbolResult.symbols; + + if (!symbols) { + return []; + } + try { + const symbolInfos = this.makeSymbolInfos(document, symbols); + return symbolInfos; + } catch (err) { + console.log(err); + return []; + } + } + + /** + * + * @param {vscode.TextDocument} document + * @param {Array} symbols + * @returns {Array} + */ + makeSymbolInfos(document: vscode.TextDocument, symbols: SymbolResult[]) { + let docSymbols = []; + const visitedSymbols = new Set(); + const moduleSymbols = symbols.filter(symbol => { + if (symbol.type == 'module') { + visitedSymbols.add(symbol); + return true; + } + return false; + }); + + for (const moduleSymbol of moduleSymbols) { + const moduleName = moduleSymbol.name; + const moduleKind = this.getSymbolKind(moduleSymbol.type); + const moduleRange = new vscode.Range(moduleSymbol.start, moduleSymbol.end); + const moduleDocSymbol = new vscode.DocumentSymbol(moduleName, + moduleName, + moduleKind, + moduleRange, + moduleRange); + docSymbols.push(moduleDocSymbol); + let paramContainer = { + docSymbol: null, + range: null + }; + let portContainer = { + docSymbol: null, + range: null + }; + + // make others in module inner + for (const symbol of symbols) { + if (visitedSymbols.has(symbol)) { + continue; + } + if (!(positionAfterEqual(symbol.start, moduleSymbol.start) && + positionAfterEqual(moduleSymbol.end, symbol.end))) { + continue; + } + if (!symbol.name) { + symbol.name = '???'; + } + visitedSymbols.add(symbol); + const symbolRange = new vscode.Range(symbol.start, symbol.end); + + if (symbol.type == 'parameter') { + if (!paramContainer.range) { + paramContainer.range = symbolRange; + paramContainer.docSymbol = new vscode.DocumentSymbol('param', + 'param description', + vscode.SymbolKind.Method, + symbolRange, + symbolRange); + moduleDocSymbol.children.push(paramContainer.docSymbol); + } + const paramDocSymbol = new vscode.DocumentSymbol(symbol.name, + symbol.type, + vscode.SymbolKind.Constant, + symbolRange, + symbolRange); + paramContainer.docSymbol.children.push(paramDocSymbol); + + } else if (['input', 'inout', 'output'].includes(symbol.type)) { + if (!portContainer.range) { + portContainer.range = symbolRange; + portContainer.docSymbol = new vscode.DocumentSymbol('port', + 'port description', + vscode.SymbolKind.Method, + symbolRange, + symbolRange); + moduleDocSymbol.children.push(portContainer.docSymbol); + } + + const portDocSymbol = new vscode.DocumentSymbol(symbol.name, + symbol.type, + vscode.SymbolKind.Interface, + symbolRange, + symbolRange); + portContainer.docSymbol.children.push(portDocSymbol); + } else { + const symbolKind = this.getSymbolKind(symbol.type); + const symbolDocSymbol = new vscode.DocumentSymbol(symbol.name, + symbol.type, + symbolKind, + symbolRange, + symbolRange); + moduleDocSymbol.children.push(symbolDocSymbol); + } + } + } + + return docSymbols; + } + + + getSymbolKind(name) { + if (name.indexOf('[') != -1) { + return vscode.SymbolKind.Array; + } + switch (name) { + case 'module': return vscode.SymbolKind.Class; + case 'program': return vscode.SymbolKind.Module; + case 'package': return vscode.SymbolKind.Package; + case 'import': return vscode.SymbolKind.Package; + case 'always': return vscode.SymbolKind.Operator; + case 'processe': return vscode.SymbolKind.Operator; + + case 'task': return vscode.SymbolKind.Method; + case 'function': return vscode.SymbolKind.Function; + + case 'assert': return vscode.SymbolKind.Boolean; + case 'event': return vscode.SymbolKind.Event; + case 'instance': return vscode.SymbolKind.Event; + + case 'time': return vscode.SymbolKind.TypeParameter; + case 'define': return vscode.SymbolKind.TypeParameter; + case 'typedef': return vscode.SymbolKind.TypeParameter; + case 'generate': return vscode.SymbolKind.Operator; + case 'enum': return vscode.SymbolKind.Enum; + case 'modport': return vscode.SymbolKind.Boolean; + case 'property': return vscode.SymbolKind.Property; + + // port + case 'interface': return vscode.SymbolKind.Interface; + case 'buffer': return vscode.SymbolKind.Interface; + case 'output': return vscode.SymbolKind.Interface; + case 'input': return vscode.SymbolKind.Interface; + case 'inout': return vscode.SymbolKind.Interface; + + // synth param + case 'localparam': return vscode.SymbolKind.Constant; + case 'parameter': return vscode.SymbolKind.Constant; + case 'integer': return vscode.SymbolKind.Number; + case 'char': return vscode.SymbolKind.Number; + case 'float': return vscode.SymbolKind.Number; + case 'int': return vscode.SymbolKind.Number; + + // unsynth param + case 'string': return vscode.SymbolKind.String; + case 'struct': return vscode.SymbolKind.Struct; + case 'class': return vscode.SymbolKind.Class; + + case 'logic': return vscode.SymbolKind.Constant; + case 'wire': return vscode.SymbolKind.Constant; + case 'reg': return vscode.SymbolKind.Constant; + case 'net': return vscode.SymbolKind.Variable; + case 'bit': return vscode.SymbolKind.Boolean; + default: return vscode.SymbolKind.Event; + } + /* Unused/Free SymbolKind icons + return SymbolKind.Number; + return SymbolKind.Enum; + return SymbolKind.EnumMember; + return SymbolKind.Operator; + return SymbolKind.Array; + */ + } +} diff --git a/src/hdlParser/core.ts b/src/hdlParser/core.ts index f393295..a83a582 100644 --- a/src/hdlParser/core.ts +++ b/src/hdlParser/core.ts @@ -188,24 +188,24 @@ class HdlParam { this.unhandleInstances.delete(inst); } - public async initHdlFiles(hdlFiles: AbsPath[] | Generator) { - for (const path of hdlFiles) { - // TODO : only support verilog now - const langID = hdlFile.getLanguageId(path); - if (langID === HdlLangID.Verilog) { - try { - const fast = await HdlSymbol.fast(path); - if (fast) { - new HdlFile(path, - fast.languageId, - fast.macro, - fast.content.modules); - } - } catch (error) { - MainOutput.report('Error happen when parse ' + path, ReportType.Error); - MainOutput.report('Reason: ' + error, ReportType.Error); - } + private async doHdlFast(path: AbsPath) { + try { + const fast = await HdlSymbol.fast(path); + if (fast) { + new HdlFile(path, + fast.languageId, + fast.macro, + fast.content); } + } catch (error) { + MainOutput.report('Error happen when parse ' + path, ReportType.Error); + MainOutput.report('Reason: ' + error, ReportType.Error); + } + } + + public async initHdlFiles(hdlFiles: AbsPath[] | Generator) { + for (const path of hdlFiles) { + this.doHdlFast(path); } } diff --git a/src/hdlParser/index.ts b/src/hdlParser/index.ts index 8552767..a6e5506 100644 --- a/src/hdlParser/index.ts +++ b/src/hdlParser/index.ts @@ -1,5 +1,7 @@ import { hdlParam } from './core'; +import { HdlSymbol } from './util'; export { - hdlParam + hdlParam, + HdlSymbol }; \ No newline at end of file diff --git a/src/manager/PL/index.ts b/src/manager/PL/index.ts index d9a09fe..9699212 100644 --- a/src/manager/PL/index.ts +++ b/src/manager/PL/index.ts @@ -40,43 +40,42 @@ class PlManage extends BaseManage { } - launch() { + public launch() { this.config.ope.launch(this.config); } - refresh() { + public simulate() { if (!this.config.terminal) { - return null; + return; } - - this.config.ope.refresh(this.config.terminal); - } - - simulate() { - if (!this.config.terminal) { - return null; - } - this.config.ope.simulate(this.config); } - build() { - if (!this.config.terminal) { - return null; - } + public simulateCli() { + this.config.ope.simulateCli(this.config); + } + public simulateGui() { + this.config.ope.simulateGui(this.config); + } + + public refresh() { + if (!this.config.terminal) { + return; + } + this.config.ope.refresh(this.config.terminal); + } + + public build() { this.config.ope.build(this.config); } - synth() { - if (!this.config.terminal) { - return null; - } + public synth() { this.config.ope.synth(this.config); } - impl() { + public impl() { if (!this.config.terminal) { return null; } @@ -84,27 +83,19 @@ class PlManage extends BaseManage { this.config.ope.impl(this.config); } - bit() { - if (!this.config.terminal) { - return null; - } - + public bitstream() { this.config.ope.generateBit(this.config); } - program() { - if (!this.config.terminal) { - return null; - } - + public program() { this.config.ope.program(this.config); } - gui() { + public gui() { this.config.ope.gui(this.config); } - exit() { + public exit() { if (!this.config.terminal) { return null; } diff --git a/src/manager/PL/xilinx.ts b/src/manager/PL/xilinx.ts index bb0f826..9bfe405 100644 --- a/src/manager/PL/xilinx.ts +++ b/src/manager/PL/xilinx.ts @@ -289,10 +289,10 @@ class XilinxOperation { } simulate(config: PLConfig) { - this.simcli(config); + this.simulateCli(config); } - simgui(config: PLConfig) { + simulateGui(config: PLConfig) { const scriptPath = `${this.xilinxPath}/simulate.tcl`; const script = ` if {[current_sim] != ""} { @@ -319,7 +319,7 @@ class XilinxOperation { config.terminal?.sendText(cmd); } - simcli(config: PLConfig) { + simulateCli(config: PLConfig) { const scriptPath = hdlPath.join(this.xilinxPath, 'simulate.tcl'); const script = ` if {[current_sim] != ""} { diff --git a/src/manager/index.ts b/src/manager/index.ts index 8fc106f..df09e3e 100644 --- a/src/manager/index.ts +++ b/src/manager/index.ts @@ -18,16 +18,33 @@ function registerManagerCommands(context: vscode.ExtensionContext) { // libpick vscode.commands.registerCommand('digital-ide.pickLibrary', pickLibrary); - // ps + // ps toolbox commands (soft tool in treeView) + // TODO : finish digital-ide.soft.download + vscode.commands.registerCommand('digital-ide.soft.launch', () => psManage.launch()); + vscode.commands.registerCommand('digital-ide.soft.build', () => psManage.build()); + vscode.commands.registerCommand('digital-ide.soft.download', () => psManage.program()); + + // pl functional commands vscode.commands.registerCommand('digital-ide.pl.setSrcTop', (item) => plManage.setSrcTop(item)); vscode.commands.registerCommand('digital-ide.pl.setSimTop', (item) => plManage.setSimTop(item)); vscode.commands.registerCommand('digital-ide.pl.addDevice', () => plManage.addDevice()); vscode.commands.registerCommand('digital-ide.pl.delDevice', () => plManage.delDevice()); vscode.commands.registerCommand('digital-ide.pl.addFile', files => plManage.addFiles(files)); vscode.commands.registerCommand('digital-ide.pl.delFile', files => plManage.delFiles(files)); - - // pl + // pl toolbox commands (hard tool in treeView) + vscode.commands.registerCommand('digital-ide.hard.launch', () => plManage.launch()); + vscode.commands.registerCommand('digital-ide.hard.simulate', () => plManage.simulate()); + vscode.commands.registerCommand('digital-ide.hard.simulate.cli', () => plManage.simulateCli()); + vscode.commands.registerCommand('digital-ide.hard.simulate.gui', () => plManage.simulateGui()); + vscode.commands.registerCommand('digital-ide.hard.refresh', () => plManage.refresh()); + vscode.commands.registerCommand('digital-ide.hard.build', () => plManage.build()); + vscode.commands.registerCommand('digital-ide.hard.build.synth', () => plManage.synth()); + vscode.commands.registerCommand('digital-ide.hard.build.impl', () => plManage.impl()); + vscode.commands.registerCommand('digital-ide.hard.build.bitstream', () => plManage.bitstream()); + vscode.commands.registerCommand('digital-ide.hard.program', () => plManage.program()); + vscode.commands.registerCommand('digital-ide.hard.gui', () => plManage.gui()); + vscode.commands.registerCommand('digital-ide.hard.exit', () => plManage.exit()); } export {