@imc-trading/svlangserver
Version:
A language server for systemverilog
886 lines (885 loc) • 41.7 kB
JavaScript
"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;