/* eslint-disable @typescript-eslint/naming-convention */ import * as vscode from 'vscode'; import { AbsPath } from '../../../global'; import { HdlLangID } from '../../../global/enum'; import { hdlPath, hdlFile } from '../../../hdlFs'; import { Range } from '../../../hdlParser/common'; const vlogNumberReg = { 'h' : /[0-9]+?'h([0-9a-fA-F_]+)/g, 'b' : /[0-9]+?'b([0-1_]+)/g, 'o' : /[0-9]+?'o([0-7_]+)/g, }; const vhdlNumberReg = { 'h' : /x"([0-9a-fA-F_]+)"/g, 'b' : /([0-1_]+)"/g, }; interface vlogNumber { unsigned: number signed: number }; /** * @description recognize and transfer number * @param lineText * @param character */ function transferVlogNumber(lineText: string, character: number): vlogNumber | undefined { let numberReg = /[0-9]/; let opt = null; let numberString = null; if (numberReg.test(lineText[character])) { const leftPart = []; const rightPart = []; const length = lineText.length; for (let i = character - 1; i >= 0; -- i) { const ch = lineText[i]; if (numberReg.test(ch)) { leftPart.push(ch); } else if (Object.keys(vlogNumberReg).includes(ch)) { if (i === 0) { return undefined; } else if (lineText[i - 1] === "'") { opt = ch; break; } else { return undefined; } } else { return undefined; } } for (let i = character + 1; i < length; ++ i) { const ch = lineText[i]; if (numberReg.test(ch)) { rightPart.push(ch); } else { break; } } const leftWord = leftPart.reverse().join(''); const rightWord = rightPart.join(''); numberString = leftWord + lineText[character] + rightWord; } else { return undefined; } if (opt && numberString) { return string2num(numberString, opt); } else { return undefined; } } /** * @description 将数字字符串转数字(包括有符号与无符号) * @param str 数字字符串 * @param opt 需要转换的进制 hex | bin | oct */ function string2num(str: string, opt: string): vlogNumber { let optNumber = -1; switch (opt) { case 'h': optNumber = 16; break; case 'b': optNumber = 2; break; case 'o': optNumber = 8; break; default: break; } let unsigned = parseInt(str, optNumber); let pow = Math.pow(optNumber, str.length); let signed = unsigned; if (unsigned >= pow >> 1) { signed = unsigned - pow; } return { 'unsigned' : unsigned, 'signed' : signed, }; } /** * @description 将二进制字符串转浮点数 * @param bin * @param exp * @param fra */ function bin2float(bin: string, exp: number, fra: number): number | undefined { if (bin.length < exp + fra +1) { return; } else { const bais = Math.pow(2, (exp-1))-1; exp = exp - bais; return exp; } } async function getFullSymbolInfo(document: vscode.TextDocument, range: Range, nonblank: RegExp, l_comment_symbol: string, l_comment_regExp: RegExp): Promise { const comments = []; let content = ''; let is_b_comment = false; let line = range.start.line; const firstLine = range.start.line - 1; while (line) { line --; content = document.lineAt(line).text; // 首先判断该行是否是空白 let isblank = content.match(nonblank); if (!isblank) { continue; } if (is_b_comment) { let b_comment_begin_index = content.indexOf('/*'); if (b_comment_begin_index === -1) { comments.push(content + '\n'); continue; } comments.push(content.slice(b_comment_begin_index, content.length) + '\n'); is_b_comment = false; content = content.slice(0, b_comment_begin_index); if (content.match(nonblank)) { break; } continue; } // 判断该行是否存在行注释 let l_comment_index = content.indexOf(l_comment_symbol); if (l_comment_index >= 0) { let before_l_comment = content.slice(0, l_comment_index); // before_l_comment = del_comments(before_l_comment, b_comment_end_index); if (before_l_comment.match(nonblank)) { // 如果去除块注释之后还有字符则认为该注释不属于所要的 if (line === firstLine) { // let b_comment_last_index = content.lastIndexOf('*/'); // b_comment_last_index = (b_comment_last_index == -1) ? 0 : (b_comment_last_index + 2); // comments.push(content.slice(b_comment_last_index, l_comment_index) + '\n'); comments.push(content.slice(l_comment_index, content.length) + '\n'); continue; } break; } // 否则该行全为该定义的注释 comments.push(content + '\n'); continue; } // 判断该行是否存在块注释 let b_comment_end_index = content.indexOf('*/'); if (b_comment_end_index >= 0) { b_comment_end_index += 2; let behind_b_comment = content.slice(b_comment_end_index, content.length); behind_b_comment = del_comments(behind_b_comment, l_comment_regExp); if (behind_b_comment.match(nonblank)) { // 如果去除块注释之后还有字符则认为该注释不属于所要的 if (line === firstLine) { comments.push(content.slice(0, b_comment_end_index) + '\n'); is_b_comment = true; continue; } break; } comments.push(content + '\n'); is_b_comment = true; continue; } // 说明既不是块注释又不是行注释所以就是到了代码块 if (line !== firstLine) { break; } } // 清除空前行 let resultComment = ''; for (const c of comments.reverse()) { resultComment += c.trim() + '\n'; } return resultComment; } /** * @description get definition and comment of a range * @param path * @param range */ async function getSymbolComment(path: AbsPath, range: Range): Promise { const languageId = hdlFile.getLanguageId(path); const uri = vscode.Uri.file(path); const documentPromise = vscode.workspace.openTextDocument(uri); // get comment reg util const nonblank = /\S+/g; const l_comment = getCommentUtilByLanguageId(languageId); if (l_comment) { const l_comment_symbol = l_comment.l_comment_symbol; const l_comment_regExp = l_comment.l_comment_regExp; // add definition first const document = await documentPromise; const symbolInfo = await getFullSymbolInfo(document, range, nonblank, l_comment_symbol, l_comment_regExp); return symbolInfo; } return null; } /** * @description get definition and comment of a range * @param path * @param ranges */ async function getSymbolComments(path: string, ranges: Range[]): Promise { let languageId = hdlFile.getLanguageId(path); const uri = vscode.Uri.file(path); const documentPromise = vscode.workspace.openTextDocument(uri); // get comment reg util const nonblank = /\S+/g; const l_comment = getCommentUtilByLanguageId(languageId); if (!l_comment) { return []; } let l_comment_symbol = l_comment.l_comment_symbol; let l_comment_regExp = l_comment.l_comment_regExp; // add definition first const document = await documentPromise; const commentPromises = []; const comments = []; for (const range of ranges) { const commentP = getFullSymbolInfo(document, range, nonblank, l_comment_symbol, l_comment_regExp); commentPromises.push(commentP); } for (const cp of commentPromises) { comments.push(await cp); } return comments; } interface CommentUtil { l_comment_symbol: string l_comment_regExp: RegExp } function getCommentUtilByLanguageId(languageId: HdlLangID): CommentUtil | undefined { switch (languageId) { case "verilog": case "systemverilog": return { l_comment_symbol: '//', l_comment_regExp: /\/\/.*/g }; case "vhdl": return { l_comment_symbol: '--', l_comment_regExp: /--.*/g }; default: return undefined; } } /** * @description delete all comment form verilog code * @param {string} text Verilog code input * @returns Verilog code output after deleting all comment content */ function del_comments(text: string, regExp: RegExp): string { let match = text.match(regExp); if (match !== null) { for (let i = 0; i < match.length; i++) { const element = match[i]; const newElement = ' '.repeat(element.length); text = text.replace(element,newElement); } } return text; } export { transferVlogNumber, getSymbolComment, getSymbolComments };