pss-langserver
Version:
A Language server for the Portable Stimulus Standard
446 lines (444 loc) • 22 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.doxygen_visitor = exports.visitor = void 0;
/*
* Copyright (C) 2025 Darshan(@thisisthedarshan)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const antlr4_1 = require("antlr4");
const pssVisitor_1 = __importDefault(require("../grammar/pssVisitor"));
const pssLex_1 = __importDefault(require("../grammar/pssLex"));
const helpers_1 = require("./helpers");
const dataTypes_1 = require("../definitions/dataTypes");
const doxygenParserVisitor_1 = __importDefault(require("../grammar/doxygenParserVisitor"));
const doxygenParser_1 = __importDefault(require("../grammar/doxygenParser"));
const doxygenLexer_1 = __importDefault(require("../grammar/doxygenLexer"));
class visitor extends pssVisitor_1.default {
/* Getters */
getIdentifiers() { return this.identifiers; }
getMeta() { return this.astMeta; }
constructor(tokenStream, fileURI) {
super();
/* Data types */
this.identifiers = [];
this.astMeta = [];
this.tokenStream = tokenStream;
/* Visit different identifiers */
this.visitIdentifier = (ctx) => {
this.identifiers.push(ctx.getText());
};
/* Visit all declarations and generate data */
this.visitAction_declaration = (ctx) => {
const comments = this.captureComments(ctx);
this.astMeta.push({
[ctx.action_identifier().identifier()?.getText()]: {
objectType: dataTypes_1.objType.ACTION,
parent: undefined,
onLine: {
file: fileURI,
lineNumber: ctx.action_identifier().identifier().start.line,
columnNumber: ctx.action_identifier().identifier().start.column
},
used: [],
documentation: "",
params: ctx.template_param_decl_list()?.getText(),
type: ctx.action_super_spec()?.getText(),
subComponents: undefined
}
});
super.visitChildren(ctx);
};
this.visitEnum_declaration = (ctx) => {
this.astMeta.push({
[ctx.enum_identifier().identifier()?.getText()]: {
objectType: dataTypes_1.objType.ENUM,
parent: undefined,
onLine: {
file: fileURI,
lineNumber: ctx.enum_identifier().identifier().start.line,
columnNumber: ctx.enum_identifier().identifier().start.column
},
used: [],
documentation: "",
params: undefined,
type: ctx.data_type()?.getText() || undefined,
subComponents: ctx.enum_item_list().map(item => item.identifier()?.getText())
}
});
super.visitChildren(ctx);
};
this.visitComponent_declaration = (ctx) => {
let compItems = [];
let compDataItems = [];
let templateParameters = [];
if (ctx.component_body_item_list()) {
compItems = ctx.component_body_item_list().map(compBodyItems => {
if (compBodyItems.abstract_action_declaration()) {
return compBodyItems.abstract_action_declaration().action_declaration().action_identifier().identifier()?.getText();
}
else if (compBodyItems.action_declaration()) {
return compBodyItems.action_declaration().action_identifier().identifier()?.getText();
}
else if (compBodyItems.component_pool_declaration()) {
return compBodyItems.component_pool_declaration().identifier()?.getText();
}
else if (compBodyItems.enum_declaration()) {
return compBodyItems.enum_declaration().enum_identifier().identifier()?.getText();
}
else if (compBodyItems.export_action()) {
return compBodyItems.export_action().action_type_identifier().type_identifier().type_identifier_elem(0)?.identifier()?.getText();
}
else if (compBodyItems.function_decl()) {
return compBodyItems.function_decl().function_prototype().function_identifier().identifier()?.getText();
}
else if (compBodyItems.procedural_function()) {
return compBodyItems.procedural_function().function_prototype().function_identifier().identifier()?.getText();
}
else if (compBodyItems.struct_declaration()) {
return compBodyItems.struct_declaration().struct_identifier().identifier()?.getText();
}
else if (compBodyItems.target_template_function()) {
return compBodyItems.target_template_function().function_prototype().function_identifier().identifier()?.getText();
}
else {
return "";
}
});
compDataItems = ctx.component_body_item_list().flatMap(compBodyItem => {
if (compBodyItem.component_data_declaration()) {
return compBodyItem.component_data_declaration().data_declaration()?.data_instantiation_list()?.map(dataInst => {
return dataInst.identifier()?.getText();
});
}
else {
return [];
}
});
}
if (ctx.template_param_decl_list()) {
if (ctx.template_param_decl_list().template_param_decl_list()) {
templateParameters = ctx.template_param_decl_list().template_param_decl_list().map(paramDecl => {
if (paramDecl.type_param_decl()) {
if (paramDecl.type_param_decl().generic_type_param_decl()) {
return {
paramType: (0, helpers_1.getObjType)("type"),
paramName: paramDecl.type_param_decl().generic_type_param_decl().identifier()?.getText(),
paramDefault: paramDecl.type_param_decl().generic_type_param_decl().type_identifier()?.type_identifier_elem(0)?.identifier()?.getText()
};
}
else {
const typeParamDecl = paramDecl.type_param_decl().category_type_param_decl();
const typeCategory = typeParamDecl.type_category();
let objStr = typeCategory.struct_kind()
? (typeCategory.struct_kind().object_kind()
? typeCategory.struct_kind().object_kind()?.getText()
: typeCategory.struct_kind()?.getText())
: typeCategory.getText();
return {
paramType: (0, helpers_1.getObjType)(objStr),
paramName: typeParamDecl.identifier()?.getText(),
paramDefault: typeParamDecl.type_identifier()?.type_identifier_elem(0)?.identifier()?.getText()
};
}
}
else {
return {
paramType: (0, helpers_1.getObjType)(paramDecl.value_param_decl()?.data_type()?.type_identifier()?.type_identifier_elem(0)?.identifier()?.getText()),
paramName: paramDecl.value_param_decl()?.identifier()?.getText(),
paramDefault: paramDecl.value_param_decl()?.constant_expression().expression()?.getText()
};
}
});
}
}
const compItemsFiltered = compItems; //.filter(item => item !== "" && !(Array.isArray(item) && item.length === 0));
const compDataItemsFiltered = compDataItems; //.filter(item => item !== "" && !(Array.isArray(item) && item.length === 0));
this.astMeta.push({
[ctx.component_identifier().identifier().getText()]: {
objectType: dataTypes_1.objType.COMPONENT,
parent: undefined,
onLine: {
file: fileURI,
lineNumber: ctx.component_identifier().identifier().start.line,
columnNumber: ctx.component_identifier().identifier().start.column
},
used: [],
documentation: "",
params: templateParameters,
type: ctx.component_super_spec()?.type_identifier()?.type_identifier_elem(0)?.identifier()?.getText() || undefined,
subComponents: [...compItemsFiltered, ...compDataItemsFiltered]
}
});
super.visitChildren(ctx);
};
this.visitData_declaration = (ctx) => {
if (ctx.data_instantiation_list()) {
ctx.data_instantiation_list().map(dataInstance => {
this.astMeta.push({
[dataInstance.identifier()?.getText()]: {
objectType: dataTypes_1.objType.DATA,
parent: undefined,
onLine: {
file: fileURI,
lineNumber: dataInstance.identifier().start.line,
columnNumber: dataInstance.identifier().start.column
},
used: [],
documentation: "",
params: dataInstance.array_dim()?.constant_expression()?.getText() || undefined,
type: dataInstance.constant_expression()?.getText() || undefined,
subComponents: undefined
}
});
});
}
else {
this.astMeta.push({
[ctx.data_instantiation(0)?.identifier()?.getText()]: {
objectType: dataTypes_1.objType.DATA,
parent: undefined,
onLine: {
file: fileURI,
lineNumber: ctx.data_instantiation(0)?.identifier().start.line,
columnNumber: ctx.data_instantiation(0)?.identifier().start.column
},
used: [],
documentation: "",
params: ctx.data_instantiation(0)?.array_dim()?.constant_expression()?.getText() || undefined,
type: ctx.data_instantiation(0)?.constant_expression()?.getText() || undefined,
subComponents: undefined
}
});
}
super.visitChildren(ctx);
};
this.visitProcedural_function = (ctx) => {
this.astMeta.push({
[ctx.function_prototype().function_identifier().identifier()?.getText()]: {
objectType: dataTypes_1.objType.PROCEDURAL_FUNCTION,
parent: undefined,
onLine: {
file: fileURI,
lineNumber: ctx.function_prototype().function_identifier().identifier().start.line,
columnNumber: ctx.function_prototype().function_identifier().identifier().start.column
},
used: [],
documentation: "",
params: ctx.function_prototype().function_parameter_list_prototype().function_parameter_list().map(paramList => {
let dataType = paramList.data_type()
? paramList.data_type()?.getText()
: paramList.type_category()
? (paramList.type_category().struct_kind()?.object_kind()?.getText() ||
paramList.type_category().struct_kind()?.getText() ||
paramList.type_category()?.getText())
: paramList.TOKEN_STRUCT()
? paramList.TOKEN_STRUCT()?.getText()
: paramList.TOKEN_TYPE()?.getText();
return {
paramType: (0, helpers_1.getObjType)(dataType),
paramName: paramList.identifier()?.getText(),
paramDefault: paramList.constant_expression()?.expression()?.getText() ?? ""
};
}),
type: ctx.function_prototype().function_return_type()?.getText(),
subComponents: undefined
}
});
super.visitChildren(ctx);
};
this.visitEnum_item = (ctx) => {
this.identifiers.push(ctx.getText());
};
}
captureComments(ctx, name = '') {
/* Get start token index */
const tokenIndex = ctx.start.tokenIndex;
/* Get comments before this rule */
const comments = this.getCommentsBeforeToken(tokenIndex);
if (this.tokenStream.get(ctx.start.tokenIndex - 1).channel === pssLex_1.default.TOKEN_DOC_COMMENT) {
let inputStream = new antlr4_1.CharStream(comments.join('\n'));
let lexer = new doxygenLexer_1.default(inputStream);
let tokenStream = new antlr4_1.CommonTokenStream(lexer);
let parser = new doxygenParser_1.default(tokenStream);
parser.removeErrorListeners();
let tree = parser.documentation_comment();
let visitor = new doxygen_visitor(name, false);
tree.accept(visitor);
return visitor.getComment();
}
return comments?.join('\n');
}
getInlineComments(ctx) {
const comments = [];
/* Check if stop exists before using it */
if (!ctx.stop)
return comments;
const tokenIndex = ctx.stop.tokenIndex;
/* Look at the next token */
const nextToken = this.tokenStream.get(tokenIndex + 1);
/* Check if it's on the hidden channel and is a comment */
if (nextToken && nextToken.channel === antlr4_1.Token.HIDDEN_CHANNEL) {
const tokenType = nextToken.type;
if (tokenType === pssLex_1.default.TOKEN_SL_COMMENT ||
tokenType === pssLex_1.default.TOKEN_ML_COMMENT) {
comments.push(nextToken.text);
}
}
return comments;
}
getCommentsBeforeToken(tokenIndex) {
const comments = [];
/* Search for hidden channel tokens before the current token */
let i = tokenIndex - 1;
while (i >= 0) {
const token = this.tokenStream.get(i);
/* Check if token is on the hidden channel and is a comment */
if (token.channel === antlr4_1.Token.HIDDEN_CHANNEL) {
const tokenType = token.type;
/* Check if it's one of your comment types */
if (tokenType === pssLex_1.default.TOKEN_DOC_COMMENT ||
tokenType === pssLex_1.default.TOKEN_SL_COMMENT ||
tokenType === pssLex_1.default.TOKEN_ML_COMMENT) {
comments.unshift(token.text);
}
else {
/* Stop if we hit a non-comment hidden token (usually whitespace) */
break;
}
}
else {
/* Stop if we hit a non-hidden token */
break;
}
i--;
}
return comments;
}
}
exports.visitor = visitor;
class doxygen_visitor extends doxygenParserVisitor_1.default {
getComment() {
if (this.isFileInfo) {
return `# ${this.file}
---
**Author: ${this.author}**
Date: ${this.date}
Version ${this.version}
---
### About:
${this.brief}
${this.details.length > 0 ? '---\n' + this.details : ''}
${this.deprecates.length > 0 ? '> [!CAUTION] \n> ' + this.deprecates : ''}
`.trimStart();
}
else {
return {
brief: this.brief,
details: this.details,
name: this.name,
paramDescriptions: this.paramDescriptions,
paramNames: this.paramsNames,
paramTypes: undefined,
sees: this.sees,
returns: this.returns
};
}
}
constructor(name, isFileInfo = false) {
super();
/* File Name */
this.name = '';
/* Common and var specific comments */
this.paramsNames = [];
this.paramDescriptions = [];
this.sees = [];
this.brief = '';
this.details = '';
this.returns = '';
this.deprecates = '';
this.attention = '';
this.todo = '';
this.examples = '';
/* File specific comments */
this.file = '';
this.author = '';
this.date = '';
this.version = '';
this.isFileInfo = false;
this.isFileInfo = isFileInfo;
this.name = name;
/* This is the entry point for doxygen comment */
this.visitDocumentation_comment = (ctx) => {
if (ctx.doc_content_list()) {
/* Parse the document blocks one by one */
ctx.doc_content_list().map(doc_content => {
if (doc_content.brief_command()) {
/* Parse brief content */
this.brief = doc_content.brief_command().brief_text().getText();
}
if (doc_content.param_command()) {
/* Parse param content */
this.paramsNames.push(doc_content.param_command().param_identifier().getText());
this.paramDescriptions.push(doc_content.param_command().param_description().getText());
}
if (doc_content.return_command()) {
/* Parse return content */
this.returns = doc_content.return_command().return_description().getText();
}
if (doc_content.deprecated_command()) {
/* Parse deprecated content */
this.deprecates = doc_content.deprecated_command().deprecated_description().getText();
}
if (doc_content.author_command()) {
/* Parse author content */
this.author = doc_content.author_command().author_name().getText();
}
if (doc_content.date_command()) {
/* Parse date content */
this.date = doc_content.date_command().date_value().getText();
}
if (doc_content.version_command()) {
/* Parse version content */
this.version = doc_content.version_command().version_value().getText();
}
if (doc_content.file_command()) {
/* Parse file content */
this.file = doc_content.file_command().file_path().getText();
}
if (doc_content.see_command()) {
/* Parse see content */
this.sees.push(doc_content.see_command().see_link().getText());
}
if (doc_content.attention_command()) {
/* Parse attention content */
this.attention = doc_content.attention_command().attention_description().getText();
}
if (doc_content.todo_command()) {
/* Parse todo content */
this.todo = doc_content.todo_command().todo_description().getText();
}
if (doc_content.example_command()) {
/* Parse example content */
this.examples = doc_content.example_command().example_code().getText();
}
});
}
};
}
}
exports.doxygen_visitor = doxygen_visitor;