pss-langserver
Version:
A Language server for the Portable Stimulus Standard
125 lines (109 loc) • 4.61 kB
text/typescript
/*
* 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/>.
*/
import { Location, Position, Range } from "vscode-languageserver/node";
import { metaData, objType } from "../definitions/dataTypes";
import { EnumNode, PSSLangObjects } from "../definitions/dataStructures";
import { collectAllPSSNodes, getNodeFromNameArray } from "../parser/helpers";
export function getGoToDefinition(document: string, pos: number, ast: metaData[]): Location | null {
const keyword = wordAt(document, pos);
let location: Location | null = null;
if (keyword === null) {
return null;
}
/* Iterate through each metaData object in the array */
for (const metaInfoObj of ast) {
/* Check if the searchString matches any key in the current metaData object */
const matchingKey = Object.keys(metaInfoObj).find(key => key === keyword);
/* If a match is found, return the location */
if (matchingKey) {
const info = metaInfoObj[matchingKey];
/* Subtracting 1 from line number since Antlr starts line number from 1 and we expect from 0 */
let start_range = Position.create(info.onLine.lineNumber - 1, info.onLine.columnNumber)
let end_range = Position.create(info.onLine.lineNumber - 1, info.onLine.columnNumber + keyword.length)
location = Location.create(
info.onLine.file,
Range.create(start_range, end_range)
);
return location;
}
}
return location;
}
export function getGoToDefinitionAdvanced(document: string, pos: number, ast: PSSLangObjects[]): Location | null {
const keyword = wordAt(document, pos);
let location: Location | null = null;
if (keyword === null) {
return null;
}
const node = getNodeFromNameArray(ast, keyword, [objType.ASSIGNMENT, objType.FUNCTION_CALL]);
if (node) {
if (node.definedOn) {
let start_range = Position.create(node.definedOn.lineNumber - 1, node.definedOn.columnNumber)
let end_range = Position.create(node.definedOn.lineNumber - 1, node.definedOn.columnNumber + keyword.length)
location = Location.create(
node.definedOn.file,
Range.create(start_range, end_range)
);
}
} else {
const enumNodes = collectAllPSSNodes(ast, { type: objType.ENUM });
if (enumNodes) {
for (const enumNode of enumNodes as EnumNode[]) {
const enumItem = enumNode.enumItems.find(item => keyword === item.name);
if (enumItem) {
let start_range = Position.create(enumItem.definedOn.lineNumber - 1, enumItem.definedOn.columnNumber)
let end_range = Position.create(enumItem.definedOn.lineNumber - 1, enumItem.definedOn.columnNumber + keyword.length)
location = Location.create(
enumItem.definedOn.file,
Range.create(start_range, end_range)
);
return location;
}
}
}
}
return location;
}
export function getReferencesAdvanced(document: string, pos: number, ast: PSSLangObjects[]): Location[] | null | undefined {
let references: Location[] = [];
const keyword = wordAt(document, pos);
if (keyword === null) {
return undefined;
}
const items = collectAllPSSNodes(ast, { name: keyword }, { skipType: objType.INSTANCE });
items.forEach(node => {
let start_range = Position.create(node.definedOn.lineNumber - 1, node.definedOn.columnNumber)
let end_range = Position.create(node.definedOn.lineNumber - 1, node.definedOn.columnNumber + keyword.length)
references.push(Location.create(
node.definedOn.file,
Range.create(start_range, end_range)
));
});
return references;
}
export function wordAt(text: string, offset: number): string | null {
const wordRegex = /\b[a-zA-Z_][a-zA-Z0-9_]*\b/g;
let match;
while ((match = wordRegex.exec(text))) {
const start = match.index;
const end = start + match[0].length;
if (offset >= start && offset <= end) {
return match[0]; // Return the matched word
}
}
return null;
}