Skip to content

Commit

Permalink
Merge pull request #4 from chrispahm/get-quoted-element-set
Browse files Browse the repository at this point in the history
Get set at position of a matching quoted element
  • Loading branch information
chrispahm authored Oct 5, 2023
2 parents 82e03d4 + 2e54ce3 commit cbe167f
Show file tree
Hide file tree
Showing 7 changed files with 1,341 additions and 10 deletions.
2 changes: 1 addition & 1 deletion dist/gams-ide.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/gams-ide.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "gams-ide",
"displayName": "gams-ide",
"description": "A GAMS integrated development environment for vscode",
"version": "0.0.42",
"version": "0.0.51",
"repository": {
"type": "git",
"url": "https://github.com/chrispahm/gams-ide"
Expand Down
67 changes: 60 additions & 7 deletions src/getSymbolUnderCursor.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
const vscode = require("vscode");
const gamsParser = require('./utils/gamsParser.js');

module.exports = async function getSymbolUnderCursor(args) {
const {
event,
event,
gamsSymbolView,
state,
gamsView
Expand Down Expand Up @@ -31,16 +32,64 @@ module.exports = async function getSymbolUnderCursor(args) {

// find the word in the reference tree
const referenceTree = state.get("referenceTree");
const solves = state.get("solves")
const matchingRef = referenceTree?.find((item) => item.name?.toLowerCase() === word?.toLowerCase());
const position = editor.selection.active;
const solves = state.get("solves")

// const position = editor.selection.active;
const line = position.line;
const column = position.character;
const file = document.fileName;

let quotedElement = "";
let functionName = "";
let domain = [];
let domainIndex = 0;

// first, we try to find the reference in the reference tree without checking the AST
let matchingRef = referenceTree?.find(
(item) => item.name?.toLowerCase() === word?.toLowerCase()
);
const { text: lineText } = document.lineAt(line);
let ast = [];
try {
ast = gamsParser.parse(lineText);
} catch (error) {
console.log("Error parsing line: ", error);
}
if (ast) {
// parse the line using the PEG parser
const gamsSymbol = ast.find((functionCall) => functionCall.args?.find(
(arg) => arg?.name?.toLowerCase().includes(word?.toLowerCase())
&& arg.start <= column
&& arg.end >= column
));
const arg = gamsSymbol?.args?.find(
(arg) => arg?.name?.toLowerCase().includes(word?.toLowerCase())
&& arg.start <= column
&& arg.end >= column
);
if (gamsSymbol) {
const functionRef = referenceTree?.find((item) => item.name?.toLowerCase() === gamsSymbol?.name?.toLowerCase());
if (arg.isQuoted) {
quotedElement = arg.name;
}
functionName = gamsSymbol.name;
domain = functionRef?.domain?.map((domain) => domain.name);
domainIndex = arg.index;

if (!matchingRef) {
matchingRef = functionRef.domain[arg.index]
}
}
}


if (matchingRef && gamsView) {
state.update("curSymbol", {
...matchingRef,
quotedElement,
functionName,
functionDomain: domain,
functionDomainIndex: domainIndex,
historyCursorFile: file,
historyCursorLine: line + 1,
historyCursorColumn: column + 1
Expand All @@ -49,8 +98,12 @@ module.exports = async function getSymbolUnderCursor(args) {
gamsView.webview.postMessage({
command: "updateReference",
data: {
...matchingRef,
historyCursorFile: file,
...matchingRef,
quotedElement,
functionName,
functionDomain: domain,
functionDomainIndex: domainIndex,
historyCursorFile: file,
historyCursorLine: line,
historyCursorColumn: column
},
Expand All @@ -72,7 +125,7 @@ module.exports = async function getSymbolUnderCursor(args) {
//}
// only update symbol view if it enabled in the settings
const isSymbolParsingEnabled = vscode.workspace.getConfiguration("gamsIde").get("parseSymbolValues");
if (matchingRef && gamsSymbolView && isSymbolParsingEnabled) {
if (matchingRef && gamsSymbolView && isSymbolParsingEnabled) {
gamsSymbolView.webview.postMessage({
command: "updateSolveData",
data: {
Expand Down
134 changes: 134 additions & 0 deletions src/utils/buildGamsParser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
const PEG = require("./peg.js");
const fs = require("fs");
const document = {}

const grammar = `
input
= parts:(functionCall / ignored / alsoIgnored)* {
let result = [];
for (let i = 0; i < parts.length; i++) {
if (parts[i].type === "functionCall") {
result.push(parts[i]);
}
}
return result;
}
functionCall
= name:identifier "(" args:argumentList ")" {
return {type: "functionCall", name: name.name, args: args};
}
argumentList
= head:(_ argument _) tail:((",") _ argument _)* {
const loc = location();
const startCol = loc.start.column;
const wsBefore = head[0].length;
const name = head[1].name
const nameLength = name.length + head[1].wsCount;
const wsAfter = head[2].length;
let curEnd = startCol + wsBefore + nameLength + wsAfter;
let result = [{
name,
isQuoted: head[1].isQuoted,
start: startCol,
end: curEnd,
index: 0
}];
for (let i = 0; i < tail.length; i++) {
const startCol = curEnd + 1;
const wsBefore = tail[i][1].length;
const name = tail[i][2].name
const nameLength = name.length + tail[i][2].wsCount;
const wsAfter = tail[i][3].length;
curEnd = startCol + wsBefore + nameLength + wsAfter;
result.push({
name,
isQuoted: tail[i][2].isQuoted,
start: startCol,
end: curEnd,
index: i + 1
});
}
return result;
}
/ "" { return []; }
argument
= identifier / stringLiteral / numberLiteral
_ "whitespace"
= [ \t\n\r]*
identifier
= first:letter rest:letterOrDigitOrSpecial* {
return {
name: first + rest.join(""),
isQuoted: false,
wsCount: 0
}
}
stringLiteral
= "\"" chars:doubleChar* "\"" {
return {
name: chars.join(""),
isQuoted: true,
wsCount: 2
}
}
/ "\'" chars:singleChar* "\'" {
return {
name: chars.join(""),
isQuoted: true,
wsCount: 2
}
}
numberLiteral
= digits:[0-9]+ {
return {
name: parseInt(digits.join(""), 10),
wsCount: 0
}
}
letter
= [a-zA-Z]
letterOrDigitOrSpecial
= [a-zA-Z0-9_]
doubleChar
= [^("|\n)] / "\\\"" // this will match any character except a double quote or a newline, or an escaped double quote
singleChar
= [^('|\n)] / "\\'" // this will match any character except a single quote or a newline, or an escaped single quote
ignored
= chars:[^a-zA-Z0-9_]+ { // this will ignore any characters that are not a letter, digit, or underscore
return {type: "ignored", value: chars.join("")};
}
alsoIgnored
= chars:[^+*-/=; ]+ { // this will ignore any characters that are not a letter, digit, or underscore
return {type: "ignored", value: chars.join("")};
}
`


const parserSource = PEG.buildParser(grammar, {
cache: true,
trackLineAndColumn: true,
partialMatch: true,
output: "source"
});

const res = `
const document = {};
module.exports = ${parserSource}
`
fs.writeFileSync("./gamsParser.js", res);
Loading

0 comments on commit cbe167f

Please sign in to comment.