UNPKG

@imc-trading/svlangserver

Version:
886 lines (885 loc) 41.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SystemVerilogPreprocessor = exports.PostToken = void 0; const node_1 = require("vscode-languageserver/node"); const genutils_1 = require("./genutils"); const grammar_engine_1 = require("./grammar_engine"); const svpreproc_grammar_1 = require("./svpreproc_grammar"); const svsymbol_1 = require("./svsymbol"); const path = require("path"); var MacroAction; (function (MacroAction) { MacroAction[MacroAction["Add"] = 0] = "Add"; MacroAction[MacroAction["Del"] = 1] = "Del"; MacroAction[MacroAction["DelAll"] = 2] = "DelAll"; })(MacroAction || (MacroAction = {})); class PostToken { } exports.PostToken = PostToken; class ReplToken extends grammar_engine_1.GrammarToken { } const DEBUG_MODE = 0; class PreprocTokenManager { constructor(tokens) { this._preTokens = tokens; this._currTokenNum = 0; this._tokensPending = tokens.length > 0; } getCurrToken() { return this._preTokens[this._currTokenNum]; } nextToken() { if (this._currTokenNum < (this._preTokens.length - 1)) { this._currTokenNum++; } else { this._tokensPending = false; } } prevToken(tokenMarker) { if (this._currTokenNum == 0) { genutils_1.ConnectionLogger.error(`cannot go before first token`); } else if (tokenMarker != undefined) { this._currTokenNum = tokenMarker; this._tokensPending = true; } else if (this._tokensPending) { this._currTokenNum--; } else { this._tokensPending = true; } } tokensPending() { return this._tokensPending; } getCurrTokenMarker() { return this._currTokenNum; } getEmptyPostToken(tokenMarker) { let startTokenMarker = (tokenMarker == undefined) ? this._currTokenNum : tokenMarker; if ('endIndex' in this._preTokens[this._currTokenNum]) { return { text: " ", index: this._preTokens[startTokenMarker].index, endIndex: this._preTokens[this._currTokenNum].endIndex }; } else { return { text: " ", index: this._preTokens[startTokenMarker].index, endIndex: this._preTokens[this._currTokenNum].index + this._preTokens[this._currTokenNum].text.length - 1 }; } } getCurrPostToken() { if ('endIndex' in this._preTokens[this._currTokenNum]) { return { text: this._preTokens[this._currTokenNum].text, index: this._preTokens[this._currTokenNum].index, endIndex: this._preTokens[this._currTokenNum].endIndex }; } else { return { text: this._preTokens[this._currTokenNum].text, index: this._preTokens[this._currTokenNum].index, endIndex: this._preTokens[this._currTokenNum].index + this._preTokens[this._currTokenNum].text.length - 1 }; } } getRange(document, startTokenMarker, endTokenMarker) { let endTokenNum = endTokenMarker || this._currTokenNum; if ('endIndex' in this._preTokens[this._currTokenNum]) { return node_1.Range.create(document.positionAt(this._preTokens[startTokenMarker].index), document.positionAt(this._preTokens[endTokenNum].endIndex + 1)); } else { return node_1.Range.create(document.positionAt(this._preTokens[startTokenMarker].index), document.positionAt(this._preTokens[endTokenNum].index + this._preTokens[endTokenNum].text.length)); } } replaceTokens(startTokenMarker, newTokens) { let startIndex = this._preTokens[startTokenMarker].index; let endIndex = ('endIndex' in this._preTokens[this._currTokenNum]) ? this._preTokens[this._currTokenNum].endIndex : this._preTokens[this._currTokenNum].index + this._preTokens[this._currTokenNum].text.length - 1; let replTokens = []; if (newTokens && (newTokens.length > 0)) { replTokens = newTokens.map(token => { return { text: token.text, index: startIndex, scopes: token.scopes, endIndex: endIndex }; }); } this._preTokens.splice(startTokenMarker, this._currTokenNum - startTokenMarker + 1, ...replTokens); this._currTokenNum = startTokenMarker; } } class SystemVerilogPreprocessor { _getElem(list, index) { let _index = (index == undefined) ? list.length - 1 : index; return (list.length > _index) && (_index >= 0) ? list[_index] : undefined; } _printDebugInfo(blockId) { if (DEBUG_MODE != 1) { return; } let pos = this._document.positionAt(this._tokenManager.getCurrToken().index); genutils_1.ConnectionLogger.log(`DEBUG: Found ${blockId} at ${pos.line}, ${pos.character}`); } _pushEmptyPostToken(startTokenMarker) { this._preprocIncInfo.postTokens.push(this._tokenManager.getEmptyPostToken(startTokenMarker)); } _processMacroArgDefault() { let scopeDepth = this._tokenManager.getCurrToken().scopes.length - 1; this._tokenManager.nextToken(); let argDefault = []; let firstTokenFound = false; let tokenNum = 0; let lastTokenNum = 0; for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { let scope = this._getElem(this._tokenManager.getCurrToken().scopes, scopeDepth); if ((scope == "parantheses.close.systemverilog") || (scope == "operator.comma.systemverilog")) { this._tokenManager.prevToken(); break; } else if (firstTokenFound || (this._getElem(this._tokenManager.getCurrToken().scopes) != "meta.whitespace.systemverilog")) { argDefault.push(this._tokenManager.getCurrToken()); firstTokenFound = true; if (this._getElem(this._tokenManager.getCurrToken().scopes) != "meta.whitespace.systemverilog") { lastTokenNum = tokenNum; } } tokenNum++; } return argDefault.slice(lastTokenNum - tokenNum); } _processMacroArgs(macroInfo) { let scopeDepth = this._tokenManager.getCurrToken().scopes.length - 1; this._tokenManager.nextToken(); let argId; let argCount = 0; let argDefault; for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { let scope = this._getElem(this._tokenManager.getCurrToken().scopes, scopeDepth + 1); if ((scope == "parantheses.close.systemverilog") || (scope == "operator.comma.systemverilog")) { if (argId) { macroInfo.args.set(argId, argCount); macroInfo.default.push(argDefault); argCount++; } if (scope == "parantheses.close.systemverilog") { break; } else { argId = undefined; argDefault = undefined; } } else if (scope == "identifier.regular.systemverilog") { argId = this._tokenManager.getCurrToken().text; } else if (scope == "operator.equals.systemverilog") { argDefault = this._processMacroArgDefault(); } } } _processDefine() { let startTokenMarker = this._tokenManager.getCurrTokenMarker(); let scopeDepth = this._tokenManager.getCurrToken().scopes.length - 1; let scope = this._getElem(this._tokenManager.getCurrToken().scopes, scopeDepth); if ((scope != "meta.macro.systemverilog") || (this._tokenManager.getCurrToken().text != "`define")) { return false; } this._printDebugInfo("define macro"); this._tokenManager.nextToken(); let macroName; let macroNameMarker; let macroInfo = { args: undefined, default: undefined, definition: [], symbol: undefined, file: this._filePath }; let checkArgsList = true; for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { scope = this._getElem(this._tokenManager.getCurrToken().scopes, scopeDepth); let topScope = this._getElem(this._tokenManager.getCurrToken().scopes); if ((topScope == "meta.whitespace.systemverilog") && /\n|\r/.exec(this._tokenManager.getCurrToken().text)) { break; } else if (topScope == "comment.line.systemverilog") { break; } else if (macroName) { if (checkArgsList && (scope == "parantheses.open.systemverilog")) { macroInfo.args = new Map(); macroInfo.default = []; this._processMacroArgs(macroInfo); checkArgsList = false; } else if (checkArgsList && (topScope != "meta.whitespace.systemverilog")) { macroInfo.definition.push(this._tokenManager.getCurrToken()); checkArgsList = false; } else if (!checkArgsList) { macroInfo.definition.push(this._tokenManager.getCurrToken()); } } else if (scope == "identifier.regular.systemverilog") { macroName = this._tokenManager.getCurrToken().text; macroNameMarker = this._tokenManager.getCurrTokenMarker(); } } if (macroName) { macroInfo.symbol = new svsymbol_1.SystemVerilogSymbol(macroName, this._tokenManager.getRange(this._document, startTokenMarker), this._tokenManager.getRange(this._document, macroNameMarker, macroNameMarker), ["source.systemverilog"], ["macro"]); if (this._macroInfo.has(macroName)) { this._macroInfo.delete(macroName); this._preprocIncInfo.macroChanges.push({ action: MacroAction.Del, macroName: macroName, macroInfo: undefined }); } this._macroInfo.set(macroName, macroInfo); this._preprocIncInfo.macroChanges.push({ action: MacroAction.Add, macroName: macroName, macroInfo: macroInfo }); } this._pushEmptyPostToken(startTokenMarker); return true; } _processNoArgDirectives() { let scope = this._getElem(this._tokenManager.getCurrToken().scopes); let tokenText = this._tokenManager.getCurrToken().text; if ((scope != "meta.macro.systemverilog") || ((tokenText != "`resetall") && (tokenText != "`undefineall") && (tokenText != "`nounconnected_drive") && (tokenText != "`celldefine") && (tokenText != "`endcelldefine") && (tokenText != "`__FILE__") && (tokenText != "`__LINE__") && (tokenText != "`end_keywords"))) { return false; } if (tokenText == "`undefineall") { this._macroInfo = new Map(); this._preprocIncInfo.macroChanges.push({ action: MacroAction.DelAll, macroName: undefined, macroInfo: undefined }); } this._pushEmptyPostToken(); return true; } _processSingleArgDirectives() { let startTokenMarker = this._tokenManager.getCurrTokenMarker(); let scope = this._getElem(this._tokenManager.getCurrToken().scopes); let tokenText = this._tokenManager.getCurrToken().text; if ((scope != "meta.macro.systemverilog") || ((tokenText != "`undef") && (tokenText != "`default_nettype") && (tokenText != "`unconnected_drive"))) { return false; } this._printDebugInfo("single arg directive"); this._tokenManager.nextToken(); for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { if (this._getElem(this._tokenManager.getCurrToken().scopes) != "meta.whitespace.systemverilog") { break; } } if (tokenText == "`undef") { this._macroInfo.delete(this._tokenManager.getCurrToken().text); this._preprocIncInfo.macroChanges.push({ action: MacroAction.Del, macroName: this._tokenManager.getCurrToken().text, macroInfo: undefined }); } this._pushEmptyPostToken(startTokenMarker); return true; } _processTimescaleDirective() { let startTokenMarker = this._tokenManager.getCurrTokenMarker(); let scope = this._getElem(this._tokenManager.getCurrToken().scopes); if ((scope != "meta.macro.systemverilog") || (this._tokenManager.getCurrToken().text != "`timescale")) { return false; } this._printDebugInfo("timescale directive"); this._tokenManager.nextToken(); let numTokens = 0; for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { if (this._getElem(this._tokenManager.getCurrToken().scopes) != "meta.whitespace.systemverilog") { numTokens++; if (numTokens == 5) { break; } } } this._pushEmptyPostToken(startTokenMarker); return true; } _processPragmaDirective() { let startTokenMarker = this._tokenManager.getCurrTokenMarker(); let scope = this._getElem(this._tokenManager.getCurrToken().scopes); if ((scope != "meta.macro.systemverilog") || (this._tokenManager.getCurrToken().text != "`pragma")) { return false; } this._printDebugInfo("pragma directive"); this._tokenManager.nextToken(); for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { let topScope = this._getElem(this._tokenManager.getCurrToken().scopes); if ((topScope == "meta.whitespace.systemverilog") && /\n|\r/.exec(this._tokenManager.getCurrToken().text)) { break; } else if (topScope == "comment.line.systemverilog") { break; } } this._pushEmptyPostToken(startTokenMarker); return true; } _processLineDirective() { let startTokenMarker = this._tokenManager.getCurrTokenMarker(); let scope = this._getElem(this._tokenManager.getCurrToken().scopes); if ((scope != "meta.macro.systemverilog") || (this._tokenManager.getCurrToken().text != "`line")) { return false; } this._printDebugInfo("line directive"); this._tokenManager.nextToken(); for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { let topScope = this._getElem(this._tokenManager.getCurrToken().scopes); if (topScope == "identifier.regular.systemverilog") { break; } } this._tokenManager.nextToken(); for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { let topScope = this._getElem(this._tokenManager.getCurrToken().scopes); if (topScope == "string.end.systemverilog") { break; } } this._tokenManager.nextToken(); for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { let topScope = this._getElem(this._tokenManager.getCurrToken().scopes); if (topScope == "literal.number.systemverilog") { break; } } this._pushEmptyPostToken(startTokenMarker); return true; } _processBeginKeywordsDirective() { let startTokenMarker = this._tokenManager.getCurrTokenMarker(); let scope = this._getElem(this._tokenManager.getCurrToken().scopes); if ((scope != "meta.macro.systemverilog") || (this._tokenManager.getCurrToken().text != "`begin_keywords")) { return false; } this._printDebugInfo("begin_keywords directive"); this._tokenManager.nextToken(); for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { let topScope = this._getElem(this._tokenManager.getCurrToken().scopes); if (topScope == "string.end.systemverilog") { break; } } this._pushEmptyPostToken(startTokenMarker); return true; } _skipConditionalBlock() { let nestingLevel = 0; for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { if (this._getElem(this._tokenManager.getCurrToken().scopes) == "meta.macro.systemverilog") { let tokenText = this._tokenManager.getCurrToken().text; if ((tokenText == "`ifdef") || (tokenText == "`ifndef")) { nestingLevel++; } else { if ((nestingLevel == 0) && ((tokenText == "`elsif") || (tokenText == "`else") || (tokenText == "`endif"))) { break; } else if ((nestingLevel != 0) && (tokenText == "`endif")) { nestingLevel--; } } } } } _processConditionalDirectives() { let startTokenMarker = this._tokenManager.getCurrTokenMarker(); let scope = this._getElem(this._tokenManager.getCurrToken().scopes); let preTokenText = this._tokenManager.getCurrToken().text; if ((scope != "meta.macro.systemverilog") || ((preTokenText != "`ifdef") && (preTokenText != "`ifndef") && (preTokenText != "`elsif") && (preTokenText != "`else") && (preTokenText != "`endif"))) { return false; } this._printDebugInfo("conditional directive"); if ((preTokenText == "`ifdef") || (preTokenText == "`ifndef")) { while (this._tokenManager.tokensPending()) { let tokenText = this._tokenManager.getCurrToken().text; this._tokenManager.nextToken(); if ((tokenText == "`ifdef") || (tokenText == "`ifndef") || (tokenText == "`elsif")) { for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { if (this._getElem(this._tokenManager.getCurrToken().scopes) == "identifier.regular.systemverilog") { break; } } if (this._tokenManager.tokensPending()) { let currTokenText = this._tokenManager.getCurrToken().text; if ((((tokenText == "`ifdef") || (tokenText == "`elsif")) && (this._macroInfo.has(currTokenText))) || ((tokenText == "`ifndef") && (!this._macroInfo.has(currTokenText)))) { break; } else { this._skipConditionalBlock(); } } } else { break; } } } else if (preTokenText != "`endif") { while (this._tokenManager.tokensPending()) { this._tokenManager.nextToken(); this._skipConditionalBlock(); if (this._tokenManager.getCurrToken().text == "`endif") { this._tokenManager.nextToken(); break; } } } this._pushEmptyPostToken(startTokenMarker); return true; } _getAllMacroChanges(macroChanges, macroChangeOrder) { let allMacroChanges = []; let prevIndex = 0; for (let order of macroChangeOrder) { if (order.index > prevIndex) { allMacroChanges = allMacroChanges.concat(macroChanges.slice(prevIndex, order.index)); } let incInfo = this._preprocCache.get(order.file).info; allMacroChanges = allMacroChanges.concat(this._getAllMacroChanges(incInfo.macroChanges, incInfo.macroChangeOrder)); prevIndex = order.index; } if (prevIndex < macroChanges.length) { allMacroChanges = allMacroChanges.concat(macroChanges.slice(prevIndex)); } return allMacroChanges; } _applyMacroChanges(macroChanges, macroChangeOrder) { let allMacroChanges = this._getAllMacroChanges(macroChanges, macroChangeOrder); for (let macroChange of allMacroChanges) { if (macroChange.action == MacroAction.DelAll) { this._macroInfo = new Map(); } else if (macroChange.action == MacroAction.Del) { this._macroInfo.delete(macroChange.macroName); } else { this._macroInfo.set(macroChange.macroName, macroChange.macroInfo); } } } _processIncludeDirective() { let startTokenMarker = this._tokenManager.getCurrTokenMarker(); let scope = this._getElem(this._tokenManager.getCurrToken().scopes); let preTokenText = this._tokenManager.getCurrToken().text; if ((scope != "meta.macro.systemverilog") || (preTokenText != "`include")) { return false; } this._printDebugInfo("include directive"); this._tokenManager.nextToken(); let fileName = ""; for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { let scope = this._getElem(this._tokenManager.getCurrToken().scopes); //TBD `define based include if ((scope == "string.end.systemverilog") || (this._tokenManager.getCurrToken().text == ">")) { break; } else if ((scope != "string.begin.systemverilog") && (this._tokenManager.getCurrToken().text != "<")) { fileName += this._tokenManager.getCurrToken().text; } } if (this._tokenManager.tokensPending()) { fileName = fileName.trim(); // Remove relative include components while (fileName.startsWith("./") || fileName.startsWith("../")) { if (fileName.startsWith("./")) { fileName = fileName.substring("./".length); } else if (fileName.startsWith("../")) { fileName = fileName.substring("../".length); } } let includeFilePath; let preprocIncInfo; if (this._preprocCache.has(fileName)) { let incInfo = this._preprocCache.get(fileName); includeFilePath = incInfo.file; preprocIncInfo = incInfo.info; this._applyMacroChanges(preprocIncInfo.macroChanges, preprocIncInfo.macroChangeOrder); this._preprocIncInfo.includes.add(includeFilePath); } else { for (let incFilePath of this._includeFilePaths) { if (incFilePath.endsWith(path.sep + fileName)) { includeFilePath = incFilePath; break; } } if (includeFilePath) { let allCachedIncFiles = new Map(Array.from(this._preprocCache).map(([k, v]) => [v.file, k])); if (allCachedIncFiles.has(includeFilePath)) { preprocIncInfo = this._preprocCache.get(allCachedIncFiles.get(includeFilePath)).info; let document = this._preprocCache.get(allCachedIncFiles.get(includeFilePath)).doc; this._preprocCache.set(fileName, { file: includeFilePath, info: preprocIncInfo, doc: document }); this._applyMacroChanges(preprocIncInfo.macroChanges, preprocIncInfo.macroChangeOrder); } else { try { let data = genutils_1.fsReadFileSync(includeFilePath); let document = node_1.TextDocument.create(genutils_1.pathToUri(includeFilePath), "SystemVerilog", 0, data.toString()); preprocIncInfo = (new SystemVerilogPreprocessor())._parseInc(document, this._includeFilePaths, this._preprocCache, this._macroInfo, this._fileList); let incFileSymbol = new svsymbol_1.SystemVerilogSymbol(includeFilePath, node_1.Range.create(0, 0, 0, 0), node_1.Range.create(0, 0, 0, 0), ["source.systemverilog"], ["includefile"]); preprocIncInfo.symbols.unshift(incFileSymbol); this._preprocCache.set(fileName, { file: includeFilePath, info: preprocIncInfo, doc: document }); } catch (err) { genutils_1.ConnectionLogger.warn(`Could not process include file ${includeFilePath} - ${err}`); preprocIncInfo = { symbols: [], postTokens: [], tokenOrder: [], macroChanges: [], macroChangeOrder: [], includes: new Set() }; } } this._preprocIncInfo.includes.add(includeFilePath); } else { genutils_1.ConnectionLogger.warn(`Could not find include file ${fileName}`); preprocIncInfo = { symbols: [], postTokens: [], tokenOrder: [], macroChanges: [], macroChangeOrder: [], includes: new Set() }; } } if (preprocIncInfo.postTokens.length > 0) { this._preprocIncInfo.tokenOrder.push({ file: fileName, tokenNum: this._preprocIncInfo.postTokens.length }); } if (preprocIncInfo.macroChanges.length > 0) { this._preprocIncInfo.macroChangeOrder.push({ file: fileName, index: this._preprocIncInfo.macroChanges.length }); } } this._pushEmptyPostToken(startTokenMarker); return true; } _replaceSpecialMacros(tokens) { let result = [...tokens]; for (let i = 0; i < tokens.length; i++) { let scope = this._getElem(result[i].scopes); if (scope == "macro.quote.systemverilog") { result[i] = { text: '"', index: result[i].index, scopes: [...result[i].scopes.slice(-1), "string.begin.systemverilog"] }; } else if (scope == "macro.escaped_quote.systemverilog") { result[i] = { text: '\\"', index: result[i].index, scopes: [...result[i].scopes.slice(-1), "escaped.quote.systemverilog"] }; } else if (scope == "macro.concat.systemverilog") { result[i - 1] = { text: result[i - 1].text.concat(result[i + 1].text), index: result[i - 1].index, scopes: result[i - 1].scopes }; result.splice(i, 2); i--; } else if (scope == "escaped.new_line.systemverilog") { result[i] = { text: '\n', index: result[i].index, scopes: [...result[i].scopes.slice(-1), "meta.whitespace.systemverilog"] }; } } return result; } _expandMacroCall(macroInfo, argTokens) { if (!macroInfo.definition || (macroInfo.definition.length == 0)) { return []; } let valueTokens = []; for (let i = 0; i < argTokens.length; i++) { let tokens = argTokens[i]; if ((tokens.length == 0) && (macroInfo.default.length > i) && (macroInfo.default[i].length != 0)) { valueTokens.push(macroInfo.default[i]); } else { let start = 0; for (let j = 0; j < argTokens[i].length; j++) { if (this._getElem(argTokens[i][j].scopes) != "meta.whitespace.systemverilog") { start = j; break; } } let end = 0; for (let j = argTokens[i].length - 1; j >= 0; j--) { if (this._getElem(argTokens[i][j].scopes) != "meta.whitespace.systemverilog") { end = j; break; } } valueTokens.push([...tokens].splice(start, end - start + 1)); } } let result = []; for (let i = 0; i < macroInfo.definition.length; i++) { let tokenText = macroInfo.definition[i].text; if ((this._getElem(macroInfo.definition[i].scopes) == "identifier.regular.systemverilog") && (macroInfo.args.has(tokenText))) { result = result.concat(valueTokens[macroInfo.args.get(tokenText)]); } else { result.push(macroInfo.definition[i]); } } return this._replaceSpecialMacros(result); } _processMacroCall() { let startTokenMarker = this._tokenManager.getCurrTokenMarker(); let scopeDepth = this._tokenManager.getCurrToken().scopes.length - 1; let scope = this._getElem(this._tokenManager.getCurrToken().scopes); let macroName = this._tokenManager.getCurrToken().text.slice(1); if ((scope != "meta.macro.systemverilog") || !this._macroInfo.has(macroName)) { return false; } this._printDebugInfo("macro call"); let macroInfo = this._macroInfo.get(macroName); if (macroInfo.args == undefined) { this._tokenManager.replaceTokens(startTokenMarker, this._replaceSpecialMacros(macroInfo.definition)); } else { this._tokenManager.nextToken(); for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { let scope = this._getElem(this._tokenManager.getCurrToken().scopes); if (scope == "parantheses.open.systemverilog") { break; } else if (scope != "meta.whitespace.systemverilog") { this._tokenManager.prevToken(startTokenMarker); return false; } } let argTokens = []; let currArgTokens = []; this._tokenManager.nextToken(); for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { let scope = this._getElem(this._tokenManager.getCurrToken().scopes, scopeDepth + 1); if ((scope == "operator.comma.systemverilog") || (scope == "parantheses.close.systemverilog")) { argTokens.push(currArgTokens); if (scope == "parantheses.close.systemverilog") { break; } else { currArgTokens = []; } } else { currArgTokens.push(this._tokenManager.getCurrToken()); } } this._tokenManager.replaceTokens(startTokenMarker, this._expandMacroCall(macroInfo, argTokens)); } return true; } static tokenize(preText) { try { let _grammarEngine = new grammar_engine_1.GrammarEngine(svpreproc_grammar_1.svpreproc_grammar, "meta.any.systemverilog"); return _grammarEngine.tokenize(preText); } catch (error) { genutils_1.ConnectionLogger.error(error); return []; } } _parseInc(document, includeFilePaths, preprocCache, macroInfo, fileList, text) { let preText = text || document.getText(); this._document = document; this._filePath = genutils_1.uriToPath(document.uri); this._fileList = fileList; this._includeFilePaths = includeFilePaths; this._preprocCache = preprocCache; this._preprocIncInfo = { symbols: [], postTokens: [], tokenOrder: [], macroChanges: [], macroChangeOrder: [], includes: new Set() }; this._macroInfo = macroInfo; this._tokenManager = new PreprocTokenManager(SystemVerilogPreprocessor.tokenize(preText)); if (this._fileList.has(this._filePath)) { genutils_1.ConnectionLogger.error(`include loop found`); return undefined; } else { this._fileList.add(this._filePath); } for (; this._tokenManager.tokensPending(); this._tokenManager.nextToken()) { while (this._processMacroCall()) { } if (this._processDefine() || this._processNoArgDirectives() || this._processSingleArgDirectives() || this._processTimescaleDirective() || this._processPragmaDirective() || this._processLineDirective() || this._processBeginKeywordsDirective() || this._processConditionalDirectives() || this._processIncludeDirective()) { continue; } else { if (this._tokenManager.getCurrToken().text.startsWith("`")) { genutils_1.ConnectionLogger.error(`Parsing failed for token ${this._tokenManager.getCurrToken().text} in file ${this._filePath}`); } this._preprocIncInfo.postTokens.push(this._tokenManager.getCurrPostToken()); } } for (let [macroName, macroInfo] of this._macroInfo) { if (macroInfo.file == this._filePath) { this._preprocIncInfo.symbols.push(macroInfo.symbol); } } if (DEBUG_MODE == 2) { let postText = ""; for (let token of this._getAllPostTokens(this._filePath, this._preprocIncInfo.postTokens, this._preprocIncInfo.tokenOrder)[0]) { //ConnectionLogger.log(`DEBUG: token "${token.text}" at ${token.index} - ${token.endIndex}`); postText += token.text; } genutils_1.ConnectionLogger.log(`DEBUG: New text (${preText.length}, ${postText.length})`); genutils_1.ConnectionLogger.log(`${postText}`); for (let macro of this._macroInfo) { genutils_1.ConnectionLogger.log(`DEBUG: macro=${macro[0]}`); if (macro[1].args != undefined) { if (macro[1].args.size == 0) { genutils_1.ConnectionLogger.log(` function with no args`); } else { let args = Array.from(macro[1].args).sort((n1, n2) => { return n1[1] - n2[1]; }).map(arg => arg[0]); for (let i = 0; i < args.length; i++) { let defValue; if (macro[1].default[i] == undefined) { defValue = "none"; } else if (macro[1].default[i].length == 0) { defValue = "empty"; } else { defValue = ""; for (let token of macro[1].default[i]) { defValue += token.text; } } genutils_1.ConnectionLogger.log(` arg=${args[i]}, default=${defValue}`); } } } else { genutils_1.ConnectionLogger.log(` not a function`); } if (macro[1].definition.length == 0) { genutils_1.ConnectionLogger.log(` empty replacement text`); } else { let defText = ""; for (let token of macro[1].definition) { defText += token.text; } genutils_1.ConnectionLogger.log(` - ${defText}`); } } } return this._preprocIncInfo; } _getAllPostTokens(filePath, postTokens, tokenOrder) { let allPostTokens = []; let allTokenOrder = []; let prevIndex = 0; for (let order of tokenOrder) { if (order.tokenNum > prevIndex) { allTokenOrder.push({ file: filePath, tokenNum: allPostTokens.length }); allPostTokens = allPostTokens.concat(postTokens.slice(prevIndex, order.tokenNum)); } let incInfo = this._preprocCache.get(order.file).info; let incPostTokensInfo = this._getAllPostTokens(this._preprocCache.get(order.file).file, incInfo.postTokens, incInfo.tokenOrder); for (let incTokenOrder of incPostTokensInfo[1]) { allTokenOrder.push({ file: incTokenOrder.file, tokenNum: allPostTokens.length + incTokenOrder.tokenNum }); } allPostTokens = allPostTokens.concat(incPostTokensInfo[0]); prevIndex = order.tokenNum; } if (prevIndex < postTokens.length) { allTokenOrder.push({ file: filePath, tokenNum: allPostTokens.length }); allPostTokens = allPostTokens.concat(postTokens.slice(prevIndex)); } return [allPostTokens, allTokenOrder]; } parse(document, includeFilePaths, preprocCache, macroInfo, text) { try { let preprocIncInfo = this._parseInc(document, includeFilePaths, preprocCache, macroInfo, new Set(), text); let postTokensInfo = this._getAllPostTokens(this._filePath, this._preprocIncInfo.postTokens, this._preprocIncInfo.tokenOrder); return { symbols: preprocIncInfo.symbols, postTokens: postTokensInfo[0], tokenOrder: postTokensInfo[1], includes: preprocIncInfo.includes }; } catch (error) { genutils_1.ConnectionLogger.error(error); return { symbols: [], postTokens: [], tokenOrder: [], includes: new Set() }; } } static macroInfoToJSON(macroInfo) { return [ macroInfo.args == undefined ? undefined : Array.from(macroInfo.args.entries()), macroInfo.default, macroInfo.definition, macroInfo.symbol == undefined ? undefined : macroInfo.symbol.toJSON(), macroInfo.file ]; } static macroInfoFromJSON(macroInfoJSON) { return { args: macroInfoJSON[0] == undefined ? undefined : new Map(macroInfoJSON[0]), default: macroInfoJSON[1], definition: macroInfoJSON[2], symbol: macroInfoJSON[3] == undefined ? undefined : svsymbol_1.SystemVerilogSymbol.fromJSON(genutils_1.pathToUri(macroInfoJSON[4]), macroInfoJSON[3]), file: macroInfoJSON[4] }; } static preprocIncInfoToJSON(preprocIncInfo) { try { return [ preprocIncInfo.symbols == undefined ? undefined : preprocIncInfo.symbols.map(s => s.toJSON()), preprocIncInfo.postTokens, preprocIncInfo.tokenOrder.map(to => [to.file, to.tokenNum]), preprocIncInfo.macroChanges == undefined ? undefined : preprocIncInfo.macroChanges.map(m => [m.action, m.macroName, SystemVerilogPreprocessor.macroInfoToJSON(m.macroInfo)]), preprocIncInfo.macroChangeOrder.map(mco => [mco.file, mco.index]), preprocIncInfo.includes == undefined ? undefined : [...preprocIncInfo.includes] ]; } catch (error) { genutils_1.ConnectionLogger.error(error); return [[], [], [], [], [], []]; } } static preprocIncInfoFromJSON(fileUri, preprocIncInfoJSON) { try { return { symbols: preprocIncInfoJSON[0] == undefined ? undefined : preprocIncInfoJSON[0].map(s => svsymbol_1.SystemVerilogSymbol.fromJSON(fileUri, s)), postTokens: preprocIncInfoJSON[1], tokenOrder: preprocIncInfoJSON[2].map(to => { return { file: to[0], tokenNum: to[1] }; }), macroChanges: preprocIncInfoJSON[3] == undefined ? undefined : preprocIncInfoJSON[3].map(m => { return { action: m[0], macroName: m[1], macroInfo: SystemVerilogPreprocessor.macroInfoFromJSON(m[2]) }; }), macroChangeOrder: preprocIncInfoJSON[4].map(mco => { return { file: mco[0], index: mco[1] }; }), includes: preprocIncInfoJSON[5] == undefined ? undefined : new Set(preprocIncInfoJSON[5]) }; } catch (error) { genutils_1.ConnectionLogger.error(error); return { symbols: [], postTokens: [], tokenOrder: [], macroChanges: [], macroChangeOrder: [], includes: new Set() }; } } } exports.SystemVerilogPreprocessor = SystemVerilogPreprocessor;