Skip to content

Commit 33796aa

Browse files
authored
Merge pull request #352 from codefori/fix/program_parameters
Support for free-format program parameters and related tests
2 parents 5746a86 + e8bd6ce commit 33796aa

File tree

3 files changed

+89
-26
lines changed

3 files changed

+89
-26
lines changed

language/parser.ts

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const lineTokens = (input: string, lineNumber: number, lineIndex: number): Token
2828
return tokens;
2929
}
3030

31+
const PROGRAMPARMS_NAME = `PROGRAMPARMS`;
32+
3133
export default class Parser {
3234
parsedCache: {[thePath: string]: Cache} = {};
3335
tables: TableDetail = {};
@@ -951,40 +953,48 @@ export default class Parser {
951953

952954
case `DCL-PI`:
953955
//Procedures can only exist in the global scope.
954-
if (currentProcName) {
955-
if (parts.length > 0) {
956+
if (parts.length > 0) {
957+
if (currentProcName) {
956958
currentGroup = `procedures`;
957959
currentItem = scopes[0].procedures.find(proc => proc.name === currentProcName);
960+
} else {
961+
currentItem = new Declaration(`struct`);
962+
currentItem.name = PROGRAMPARMS_NAME;
963+
}
958964

965+
if (currentItem) {
959966
const endInline = tokens.findIndex(part => part.value.toUpperCase() === `END-PI`);
960967

961-
if (currentItem) {
962-
963-
// Indicates that the PI starts and ends on the same line
964-
if (endInline >= 0) {
965-
tokens.splice(endInline, 1);
966-
currentItem.readParms = false;
967-
resetDefinition = true;
968-
}
969-
970-
currentItem.keyword = {
971-
...currentItem.keyword,
972-
...Parser.expandKeywords(tokens.slice(2))
973-
}
974-
currentItem.readParms = true;
968+
// Indicates that the PI starts and ends on the same line
969+
if (endInline >= 0) {
970+
tokens.splice(endInline, 1);
971+
currentItem.readParms = false;
972+
resetDefinition = true;
973+
}
975974

976-
currentDescription = [];
975+
currentItem.keyword = {
976+
...currentItem.keyword,
977+
...Parser.expandKeywords(tokens.slice(2))
977978
}
979+
currentItem.readParms = true;
980+
981+
currentDescription = [];
978982
}
979983
}
980984
break;
981985

982986
case `END-PI`:
983987
//Procedures can only exist in the global scope.
984-
currentItem = scopes[0].procedures.find(proc => proc.name === currentProcName);
988+
if (currentProcName) {
989+
currentItem = scopes[0].procedures.find(proc => proc.name === currentProcName);
985990

986-
if (currentItem && currentItem.type === `procedure`) {
987-
currentItem.readParms = false;
991+
if (currentItem && currentItem.type === `procedure`) {
992+
currentItem.readParms = false;
993+
resetDefinition = true;
994+
}
995+
} else if (currentItem && currentItem.name === PROGRAMPARMS_NAME) {
996+
// Assign this scopes parameters to the subitems of the program parameters struct
997+
scopes[0].parameters = currentItem.subItems;
988998
resetDefinition = true;
989999
}
9901000
break;
@@ -1202,7 +1212,7 @@ export default class Parser {
12021212
currentItem.subItems.push(currentSub);
12031213
currentSub = undefined;
12041214

1205-
if (currentItem.type === `struct`) {
1215+
if (currentItem.type === `struct` && currentItem.name !== PROGRAMPARMS_NAME) {
12061216
resetDefinition = true;
12071217
}
12081218
}

tests/suite/partial.test.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ test("Parser partial tests", { timeout }, async () => {
1717
const parser = setupParser(projectPath);
1818
const list = await getSourcesList(projectPath);
1919

20+
totalFiles += list.length;
21+
2022
for (let i = 0; i < list.length; i++) {
2123
const relativePath = list[i];
2224
const basename = path.basename(relativePath);
@@ -51,13 +53,13 @@ test("Parser partial tests", { timeout }, async () => {
5153
lengths.push(pe - ps);
5254
}
5355

54-
const lengthsAverage = lengths.reduce((a, b) => a + b, 0) / lengths.length;
55-
const total = lengths.reduce((a, b) => a + b, 0);
56-
const last = lengths[lengths.length - 1];
56+
// const lengthsAverage = lengths.reduce((a, b) => a + b, 0) / lengths.length;
57+
// const total = lengths.reduce((a, b) => a + b, 0);
58+
// const last = lengths[lengths.length - 1];
5759
// console.log(`\tAverage: ${lengthsAverage}ms, Full: ${last}ms, Total: ${total}`);
5860
// console.log(``);
5961
}
6062
}
6163

62-
console.log(`Parsed ${totalFiles} files, ${SPLIT_SIZE} each.`);
64+
console.log(`Parsed ${totalFiles} files, ${SPLIT_SIZE} times each.`);
6365
});

tests/suite/references.test.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,10 +381,14 @@ test("references_9", async () => {
381381
const cache = await parser.getDocs(uri, lines, {ignoreCache: true, withIncludes: true, collectReferences: true});
382382

383383
const procedure = cache.find(`InputIsValid`);
384-
const validationResult = procedure.scope.find(`validationResult`);
385384

385+
const validationResult = procedure.scope.find(`validationResult`);
386386
expect(validationResult.references.length).toEqual(7);
387387
expect(validationResult.references.every(ref => lines.substring(ref.offset.start, ref.offset.end) === `validationResult`)).toBe(true);
388+
389+
const comp = procedure.scope.find(`comp`);
390+
expect(comp.references.length).toEqual(2);
391+
expect(comp.references.every(ref => lines.substring(ref.offset.start, ref.offset.end) === `comp`)).toBe(true);
388392
});
389393

390394
test('references_10', async () => {
@@ -1833,4 +1837,51 @@ test('references_27_fixed_reference', async () => {
18331837

18341838
expect(offsetContent.toUpperCase()).toBe(`WCFGKEY`);
18351839
}
1840+
});
1841+
1842+
test('reference_28_parameters', async () => {
1843+
const lines = [
1844+
`**free`,
1845+
``,
1846+
`ctl-opt dftactgrp(*no);`,
1847+
``,
1848+
`dcl-pi upddept;`,
1849+
` deptno char(3);`,
1850+
` deptname char(36);`,
1851+
` mgrno char(6);`,
1852+
` admrdept char(3);`,
1853+
` location char(16);`,
1854+
`end-pi;`,
1855+
``,
1856+
`dcl-ds result qualified dim(1);`,
1857+
` success char(1);`,
1858+
`end-ds;`,
1859+
``,
1860+
`exec sql`,
1861+
` update dept`,
1862+
` set deptname = :deptname,`,
1863+
` mgrno = :mgrno,`,
1864+
` admrdept = :admrdept,`,
1865+
` location = :location`,
1866+
` where deptno = :deptno;`,
1867+
``,
1868+
`if (SQLCOD = 0);`,
1869+
` result(1).success = 'Y';`,
1870+
`else;`,
1871+
` result(1).success = 'N';`,
1872+
`endif;`,
1873+
``,
1874+
`dcl-s return char(length) inz('Y');`,
1875+
``,
1876+
`exec sql set result sets array :result for 1 rows;`,
1877+
`// Hello`,
1878+
`return;`,
1879+
].join(`\n`);
1880+
1881+
const cache = await parser.getDocs(uri, lines, { ignoreCache: true, withIncludes: true, collectReferences: true });
1882+
1883+
const deptno = cache.find(`deptno`);
1884+
expect(deptno).toBeDefined();
1885+
expect(deptno.references.length).toBe(2);
1886+
expect(deptno.references.every(ref => lines.substring(ref.offset.start, ref.offset.end) === `deptno`)).toBe(true);
18361887
});

0 commit comments

Comments
 (0)