Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/rpgle_2023_oct #265

Merged
merged 11 commits into from
Oct 20, 2023
18 changes: 17 additions & 1 deletion extension/server/src/providers/completionItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,14 @@ export default async function completionItemProvider(handler: CompletionParams):

// Look at the parms or existing structs to find a possible reference
const possibleStruct: Declaration | undefined = [
// First we search the local procedure
currentProcedure && currentProcedure.scope ? currentProcedure.scope.parameters.find(parm => parm.name.toUpperCase() === preWord && parm.subItems.length > 0) : undefined,
currentProcedure && currentProcedure.scope ? currentProcedure.scope.structs.find(struct => struct.name.toUpperCase() === preWord) : undefined,
doc.structs.find(struct => struct.name.toUpperCase() === preWord)
currentProcedure && currentProcedure.scope ? currentProcedure.scope.constants.find(struct => struct.subItems.length > 0 && struct.name.toUpperCase() === preWord) : undefined,

// Then we search the globals
doc.structs.find(struct => struct.name.toUpperCase() === preWord),
doc.constants.find(struct => struct.subItems.length > 0 && struct.name.toUpperCase() === preWord)
].find(x => x); // find the first non-undefined item

if (possibleStruct && possibleStruct.keyword[`QUALIFIED`]) {
Expand Down Expand Up @@ -191,6 +196,17 @@ export default async function completionItemProvider(handler: CompletionParams):
item.detail = constant.keywords.join(` `);
item.documentation = constant.description;
items.push(item);

if (!constant.keyword[`QUALIFIED`]) {
constant.subItems.forEach((subItem: Declaration) => {
const item = CompletionItem.create(`${subItem.name}`);
item.kind = CompletionItemKind.Property;
item.insertText = `${subItem.name}`;
item.detail = subItem.keywords.join(` `);
item.documentation = subItem.description + ` (${constant.name})`;
items.push(item);
});
}
}
};

Expand Down
28 changes: 22 additions & 6 deletions extension/server/src/providers/documentSymbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,34 @@ export default async function documentSymbolProvider(handler: DocumentSymbolPara
SymbolKind.Variable,
Range.create(def.position.line, 0, def.position.line, 0),
Range.create(def.position.line, 0, def.position.line, 0)
)),
))
);

...scope.constants
.filter(constant => constant.position && constant.position.path === currentPath)
.map(def => DocumentSymbol.create(
scope.constants
.filter(constant => constant.position && constant.position.path === currentPath)
.forEach(def => {
const constantDef = DocumentSymbol.create(
def.name,
def.keywords.join(` `).trim(),
SymbolKind.Constant,
Range.create(def.position.line, 0, def.position.line, 0),
Range.create(def.position.line, 0, def.position.line, 0)
))
);
);

if (def.subItems.length > 0) {
constantDef.children = def.subItems
.filter(subitem => subitem.position && subitem.position.path === currentPath)
.map(subitem => DocumentSymbol.create(
subitem.name,
subitem.keywords.join(` `).trim(),
SymbolKind.Property,
Range.create(subitem.position.line, 0, subitem.position.line, 0),
Range.create(subitem.position.line, 0, subitem.position.line, 0)
));
}

currentScopeDefs.push(constantDef);
})

scope.files
.filter(struct => struct.position && struct.position.path === currentPath)
Expand Down
20 changes: 11 additions & 9 deletions extension/server/src/providers/implementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,17 @@ export default async function implementationProvider(params: ImplementationParam
const cache = parser.getParsedCache(possibleUri.value);
if (cache) {
const proc = cache.find(word);
return Location.create(
proc.position.path,
Range.create(
proc.position.line,
0,
proc.position.line,
0
)
);
if (proc) {
return Location.create(
proc.position.path,
Range.create(
proc.position.line,
0,
proc.position.line,
0
)
);
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions language/linter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ export default class Linter {
opcode = statement[0].value.toUpperCase();

if ([
`ENDIF`, `ENDFOR`, `ENDDO`, `ELSE`, `ELSEIF`, `ON-ERROR`, `ENDMON`, `ENDSR`, `WHEN`, `OTHER`, `END-PROC`, `END-PI`, `END-PR`, `END-DS`, `ENDSL`
`ENDIF`, `ENDFOR`, `ENDDO`, `ELSE`, `ELSEIF`, `ON-ERROR`, `ON-EXCP`, `ENDMON`, `ENDSR`, `WHEN`, `WHEN-IS`, `WHEN-IN`, `OTHER`, `END-PROC`, `END-PI`, `END-PR`, `END-DS`, `END-ENUM`, `ENDSL`
worksofliam marked this conversation as resolved.
Show resolved Hide resolved
].includes(opcode)) {
expectedIndent -= indent;

Expand All @@ -993,7 +993,7 @@ export default class Linter {
}

if ([
`IF`, `ELSE`, `ELSEIF`, `FOR`, `FOR-EACH`, `DOW`, `DOU`, `MONITOR`, `ON-ERROR`, `ON-EXIT`, `BEGSR`, `SELECT`, `WHEN`, `OTHER`, `DCL-PROC`, `DCL-PI`, `DCL-PR`, `DCL-DS`
`IF`, `ELSE`, `ELSEIF`, `FOR`, `FOR-EACH`, `DOW`, `DOU`, `MONITOR`, `ON-ERROR`, `ON-EXCP`, `ON-EXIT`, `BEGSR`, `SELECT`, `WHEN`, `WHEN-IS`, `WHEN-IN`, `OTHER`, `DCL-PROC`, `DCL-PI`, `DCL-PR`, `DCL-DS`, `DCL-ENUM`
].includes(opcode)) {
if ([`DCL-DS`, `DCL-PI`, `DCL-PR`].includes(opcode) && oneLineTriggers[opcode].some(trigger => statement.map(t => t.value.toUpperCase()).includes(trigger))) {
//No change
Expand Down
22 changes: 16 additions & 6 deletions language/models/cache.js → language/models/cache.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { indicators1 } from "../../tests/suite";
import { CacheProps, IncludeStatement, Keywords } from "../parserTypes";
import Declaration from "./declaration";

const inds = [...Array(98).keys(), `LR`, `KL`].map(val => `IN${val.toString().padStart(2, `0`)}`).map(ind => {
Expand All @@ -8,11 +10,19 @@ const inds = [...Array(98).keys(), `LR`, `KL`].map(val => `IN${val.toString().pa
});

export default class Cache {
/**
*
* @param {import("../parserTypes").CacheProps} cache
*/
constructor(cache = {}) {
keyword: Keywords;
parameters: Declaration[];
subroutines: Declaration[];
procedures: Declaration[];
files: Declaration[];
variables: Declaration[];
structs: Declaration[];
constants: Declaration[];
sqlReferences: Declaration[];
indicators: Declaration[];
includes: IncludeStatement[];

constructor(cache: CacheProps = {}) {
/** @type {import("../parserTypes").Keywords} */
this.keyword = {};

Expand Down Expand Up @@ -62,7 +72,7 @@ export default class Cache {
structs: [...this.structs, ...second.structs],
constants: [...this.constants, ...second.constants],
sqlReferences: [...this.sqlReferences, ...second.sqlReferences],
indicators: [...this.indicators, ...second.indicators]
indicators: [...this.indicators, ...second.indicators],
});
} else {
return this;
Expand Down
41 changes: 39 additions & 2 deletions language/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ export default class Parser {
let potentialName;
let potentialNameUsed = false;

/** @type {"structs"|"procedures"} */
/** @type {"structs"|"procedures"|"constants"} */
let currentGroup;
let isFullyFree = false;

Expand Down Expand Up @@ -554,6 +554,43 @@ export default class Parser {
}
break;

case `DCL-ENUM`:
if (currentItem === undefined) {
if (parts.length > 1) {
currentItem = new Declaration(`constant`);
currentItem.name = partsLower[1];
currentItem.keywords = parts.slice(2);
currentItem.description = currentDescription.join(`\n`);

currentItem.position = {
path: file,
line: statementStartingLine
};

currentItem.range = {
start: statementStartingLine,
end: statementStartingLine
};

currentItem.readParms = true;

currentGroup = `constants`;

currentDescription = [];
}
}
break;

case `END-ENUM`:
if (currentItem && currentItem.type === `constant`) {
currentItem.range.end = statementStartingLine;

scope.constants.push(currentItem);

resetDefinition = true;
}
break;

case `DCL-DS`:
if (currentItem === undefined) {
if (parts.length > 1) {
Expand Down Expand Up @@ -882,7 +919,7 @@ export default class Parser {
}
}

if (currentItem && [`procedure`, `struct`].includes(currentItem.type)) {
if (currentItem && [`procedure`, `struct`, `constant`].includes(currentItem.type)) {
if (currentItem.readParms && parts.length > 0) {
if (parts[0].startsWith(`DCL`)) {
parts.slice(1);
Expand Down
13 changes: 12 additions & 1 deletion language/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,17 @@ const commonMatchers: Matcher[] = [
type: `word`
}
},
{
name: `WHEN-GROUP`,
match: [
{ type: `word`, match: (word) => word.toUpperCase() === `WHEN` },
worksofliam marked this conversation as resolved.
Show resolved Hide resolved
{ type: `minus` },
{ type: `word`, match: (word) => [`IN`, `IS`].includes(word.toUpperCase())},
],
becomes: {
type: `word`
}
},
{
name: `EVAL-CORR`,
match: [
Expand Down Expand Up @@ -195,7 +206,7 @@ const commonMatchers: Matcher[] = [
match: [
{ type: `word`, match: (word) => word.toUpperCase() === `ON` },
{ type: `minus` },
{ type: `word`, match: (word) => word.toUpperCase() === `ERROR` },
{ type: `word`, match: (word) => [`ERROR`, `EXCP`].includes(word.toUpperCase())},
],
becomes: {
type: `word`
Expand Down
38 changes: 38 additions & 0 deletions tests/suite/basics.js
Original file line number Diff line number Diff line change
Expand Up @@ -1078,4 +1078,42 @@ exports.exec_10 = async () => {

assert.strictEqual(cache.sqlReferences[1].name, `PMESSGS`);
assert.strictEqual(cache.sqlReferences[1].description, ``);
}

exports.enum_1 = async () => {
const lines = [
`**free`,
``,
`DCL-ENUM sizes; // 1 `,
` tiny -1;`,
` small 0;`,
` medium 1;`,
` large 2;`,
`END-ENUM;`,
``,
`DCL-ENUM jobMsgQ QUALIFIED; // 2 `,
` noWrap '*NOWRAP';`,
` wrap '*WRAP';`,
` prtWrap '*PRTWRAP';`,
`END-ENUM;`,
``,
`DCL-S cmd VARCHAR(100);`,
`DCL-S array INT(10) DIM(5);`,
`DCL-DS item QUALIFIED;`,
` size packed(5);`,
`END-DS;`,
].join(`\n`);

const parser = parserSetup();
const cache = await parser.getDocs(uri, lines, {withIncludes: true, ignoreCache: true});

assert.strictEqual(cache.constants.length, 2);

const sizes = cache.find(`sizes`);
assert.strictEqual(sizes.name, `sizes`);
assert.strictEqual(sizes.subItems.length, 4);

const jobMsgQ = cache.find(`jobMsgQ`);
assert.strictEqual(jobMsgQ.name, `jobMsgQ`);
assert.strictEqual(jobMsgQ.subItems.length, 3);
}
Loading