Skip to content

Commit

Permalink
Merge pull request #265 from codefori/feature/rpgle_2023_oct
Browse files Browse the repository at this point in the history
Feature/rpgle_2023_oct
  • Loading branch information
worksofliam authored Oct 20, 2023
2 parents e59c6b5 + 17beec2 commit 09e0df5
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 27 deletions.
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`
].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 @@ -328,7 +328,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 @@ -563,6 +563,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 @@ -891,7 +928,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` },
{ 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

0 comments on commit 09e0df5

Please sign in to comment.