UNPKG

@imc-trading/svlangserver

Version:
266 lines (265 loc) 12.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SystemVerilogDefinitionProvider = void 0; const node_1 = require("vscode-languageserver/node"); const genutils_1 = require("./genutils"); class SystemVerilogDefinitionProvider { constructor(indexer) { this._indexer = indexer; } _findNamedArg(tokenNum, svtokens) { let scopeDepth = svtokens[tokenNum].scopes.length - 1; if ((tokenNum == 0) || (scopeDepth == 0)) { return [undefined, undefined]; } let dotLocation; for (let i = tokenNum - 1; i >= 0; i--) { if (svtokens[i].text == ".") { dotLocation = i; break; } else if (svtokens[i].scopes[svtokens[i].scopes.length - 1] != "meta.whitespace.systemverilog") { return [undefined, undefined]; } } if (dotLocation == undefined) { return [undefined, undefined]; } for (let i = 0; i < svtokens[tokenNum].scopes.length; i++) { if (!svtokens[tokenNum].scopes[i].startsWith("identifier.") && (svtokens[tokenNum].scopes[i] != "parantheses.block.systemverilog") && (svtokens[tokenNum].scopes[i] != "case.body.systemverilog") && (svtokens[tokenNum].scopes[i] != "begin.block.systemverilog") && (svtokens[tokenNum].scopes[i] != "generate.block.systemverilog") && (svtokens[tokenNum].scopes[i] != "source.systemverilog")) { for (let j = tokenNum - 1; j >= 0; j--) { if (svtokens[j].scopes[scopeDepth - 1].startsWith("identifier.")) { return [svtokens[j].text, true]; } } return [undefined, undefined]; } } let instNameFound = false; let openParenFound = false; let hashOpenParenFound = false; for (let i = dotLocation - 1; i >= 0; i--) { if (svtokens[i].scopes[scopeDepth - 1].startsWith("identifier.")) { if (instNameFound || hashOpenParenFound) { return [svtokens[i].text, false]; } else { instNameFound = true; } } else if ((svtokens[i].text == "#") && openParenFound) { hashOpenParenFound = true; } else if (!openParenFound && (svtokens[i].text == "(")) { openParenFound = true; } else if (!svtokens[i].scopes[svtokens[i].scopes.length - 1].startsWith("comment.") && (svtokens[i].scopes[svtokens[i].scopes.length - 1] != "meta.whitespace.systemverilog")) { openParenFound = false; } } return [undefined, undefined]; } _getIncludeFileName(tokens, tokenNum) { let startTokenNum; for (let i = tokenNum; i >= 0; i--) { let scope = tokens[i].scopes[tokens[i].scopes.length - 1]; if (scope == "string.begin.systemverilog") { startTokenNum = i; break; } } if (startTokenNum === undefined) { return undefined; } let endTokenNum; for (let i = tokenNum; i < tokens.length; i++) { let scope = tokens[i].scopes[tokens[i].scopes.length - 1]; if (scope == "string.end.systemverilog") { endTokenNum = i; break; } } if (endTokenNum === undefined) { return undefined; } return tokens.slice(startTokenNum + 1, endTokenNum).map(t => t.text).join(''); } _getDefinition(document, position, includeUserDefines, checkPrevPosition = false) { let svtokens = this._indexer.getSystemVerilogCompletionTokens(document.uri); let extTokenNums = this._indexer.getSystemVerilogCompletionTokenNumber(document, position.line, position.character + 1); let tokenNum = extTokenNums[1]; if (tokenNum == undefined) { return [undefined, undefined]; } let scope = svtokens[tokenNum].scopes[svtokens[tokenNum].scopes.length - 1]; let parentScope = svtokens[tokenNum].scopes.length > 1 ? svtokens[tokenNum].scopes[svtokens[tokenNum].scopes.length - 2] : undefined; if (scope.startsWith("macro.")) { let defText = svtokens[tokenNum].text.slice(1).replace(/\s*\($/, ""); let result = this._indexer.getMacros(document.uri, defText); if (result.length > 0) { return [result[0][0], result[0][1][0]]; } if (includeUserDefines) { let userDefineNum = this._indexer.findUserDefine(defText); if (userDefineNum >= 0) { //DBG ConnectionLogger.log(`DEBUG: HERE with ${userDefineNum} for ${defText}`); return ["", userDefineNum]; } } return [undefined, undefined]; } else if (scope.startsWith("identifier.hierarchical.") || (extTokenNums[0] != tokenNum)) { let filePath; let symbol; let idTokens = svtokens.slice(extTokenNums[0], tokenNum + 1); [filePath, symbol] = this._indexer.getHierarchicalSymbol(document.uri, this._indexer.getHierParts(idTokens.map(t => t.text).join(''), idTokens, document.offsetAt(position) - svtokens[extTokenNums[0]].index)); if (symbol != undefined) { return [filePath, symbol]; } } else if (parentScope == "string.body.systemverilog") { let incFileName = this._getIncludeFileName(svtokens, tokenNum); if (incFileName == undefined) { return [undefined, undefined]; } return this._indexer.getIncFilePathAndSymbol(incFileName); } else if (!scope.startsWith("identifier.")) { if (checkPrevPosition && (position.character > 0)) { return this._getDefinition(document, node_1.Position.create(position.line, position.character - 1), includeUserDefines, false); } return [undefined, undefined]; } let containerName; let isRoutine; [containerName, isRoutine] = this._findNamedArg(tokenNum, svtokens); if ((containerName == undefined) || (isRoutine == undefined)) { let symText = svtokens[tokenNum].text; if (scope.startsWith("identifier.scoped.")) { let endPos = document.offsetAt(position) - svtokens[tokenNum].index; endPos = svtokens[tokenNum].text.indexOf("::", endPos > 0 ? endPos - 1 : 0); endPos = endPos < 0 ? svtokens[tokenNum].text.length : endPos; symText = svtokens[tokenNum].text.slice(0, endPos); symText = symText.replace(/::\*$/, ''); if (symText == "*") { return [undefined, undefined]; } else if (symText.indexOf("::") < 0) { return this._indexer.getPackageSymbol(symText); } } let filePath; let symbol; [filePath, symbol] = scope.startsWith("identifier.scoped.") ? this._indexer.findSymbol(document.uri, symText) : this._indexer.findScopedSymbol(document.uri, symText, position); if ((filePath == undefined) || (symbol == undefined)) { symbol = this._indexer.getContainerSymbol(svtokens[tokenNum].text); if (symbol == undefined) { return this._indexer.getPackageSymbol(svtokens[tokenNum].text); } filePath = this._indexer.getInstFilePath(svtokens[tokenNum].text); if (filePath == undefined) { return [undefined, undefined]; } return [genutils_1.pathToUri(filePath), symbol]; } return [filePath, symbol]; } else if (isRoutine) { let filePath; let symbol; let containerSymbolsInfo; [filePath, symbol, containerSymbolsInfo] = this._indexer.getContainerInfo(document.uri, containerName); if ((filePath == undefined) || (symbol == undefined) || (containerSymbolsInfo == undefined) || (containerSymbolsInfo.symbolsInfo == undefined)) { return [undefined, undefined]; } let argSymbols = containerSymbolsInfo.symbolsInfo; let filteredArgSymbols = argSymbols.filter(sym => { return sym.name == svtokens[tokenNum].text; }); if (filteredArgSymbols.length > 0) { return [filePath, filteredArgSymbols[0]]; } return [undefined, undefined]; } else { let filePath; let symbol; let containerSymbolsInfo; let instFilePath = this._indexer.getInstFilePath(containerName); if (instFilePath == undefined) { return [undefined, undefined]; } [filePath, symbol, containerSymbolsInfo] = this._indexer.getContainerInfo(genutils_1.pathToUri(instFilePath), containerName); if ((filePath == undefined) || (symbol == undefined) || (containerSymbolsInfo == undefined) || (containerSymbolsInfo.symbolsInfo == undefined)) { return [undefined, undefined]; } let containerSymbols = containerSymbolsInfo.symbolsInfo; let filteredContainerSymbols = containerSymbols.filter(sym => { return (sym.name == svtokens[tokenNum].text) && ((sym.type[0] == "port") || (sym.type[0] == "parameter-port")); }); if (filteredContainerSymbols.length > 0) { return [filePath, filteredContainerSymbols[0]]; } return [undefined, undefined]; } } getDefinitionSymbolLocation(document, position) { try { let symbolInfo = this._getDefinition(document, position, false, true); if (symbolInfo[0] == undefined) { return Promise.resolve([]); } if (symbolInfo[0] == "") { return Promise.resolve([node_1.Location.create("", node_1.Range.create(symbolInfo[1], 0, 0, 0))]); } return Promise.resolve([(symbolInfo[1]).getSymbolLocation(symbolInfo[0])]); } catch (error) { genutils_1.ConnectionLogger.error(error); return Promise.resolve([]); } } getDefinitionText(document, position) { try { let symbolInfo = this._getDefinition(document, position, true); if (symbolInfo[0] == undefined) { return [undefined, undefined]; } let header; let code; if (symbolInfo[0] == "") { header = 'User Define'; code = this._indexer.getUserDefine((symbolInfo[1])); } else if ((typeof symbolInfo[1] !== 'number') && ((symbolInfo[1]).type.indexOf("includefile") >= 0)) { header = (symbolInfo[1]).name; code = ''; } else { header = (document.uri == symbolInfo[0]) ? '' : `File: ${genutils_1.uriToPath(symbolInfo[0])}`; code = (symbolInfo[1]).getDefinition(symbolInfo[0]); } let trimLength = 0; let codeLines = code.split(/\r?\n/).map((codeLine, i) => { let lineTrimLength = codeLine.search(/\S/); lineTrimLength = (lineTrimLength < 0) ? 0 : lineTrimLength; ; if (i == 0) { trimLength = lineTrimLength; } let actTrimLength = (trimLength < lineTrimLength) ? trimLength : lineTrimLength; return codeLine.slice(actTrimLength); }); return [header, codeLines]; } catch (error) { // ConnectionLogger.error(error); // Too much noise in VSCode console return [undefined, undefined]; } } } exports.SystemVerilogDefinitionProvider = SystemVerilogDefinitionProvider;