Skip to content

Commit 421fca5

Browse files
authored
Merge pull request #354 from codefori/worksofliam/issue353
Enhance comment handling and validation in parser
2 parents 63b8ab9 + 41f2031 commit 421fca5

File tree

3 files changed

+162
-10
lines changed

3 files changed

+162
-10
lines changed

language/parser.ts

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import Declaration from "./models/declaration";
77

88
import oneLineTriggers from "./models/oneLineTriggers";
99
import { parseFLine, parseCLine, parsePLine, parseDLine, getPrettyType, prettyTypeFromToken } from "./models/fixed";
10-
import path from "path";
1110
import { Token } from "./types";
1211
import { Keywords } from "./parserTypes";
1312

@@ -357,20 +356,67 @@ export default class Parser {
357356
return directIfScope.length === 0 || directIfScope.every(scope => scope.condition);
358357
}
359358

359+
/**
360+
* Removes the trailing line comment (//) but keeps the semi-colon if found.
361+
*/
360362
const stripComment = (inputLine: string) => {
361-
const comment = inputLine.indexOf(`//`);
362-
const quote = inputLine.lastIndexOf(`'`);
363-
if (comment >= 0 && comment < quote) {
364-
return inputLine;
363+
let comment = -1;
364+
let inString = false;
365+
for (let i = inputLine.length - 1; i >= 0; i--) {
366+
switch (inputLine[i]) {
367+
case '/':
368+
if (inputLine[i-1] === `/`) {
369+
// It's a comment!
370+
inString = false;
371+
comment = i-1;
372+
i--;
373+
374+
return inputLine.substring(0, comment).trimEnd();
375+
}
376+
break;
377+
case `'`:
378+
inString = !inString;
379+
break;
380+
case ';':
381+
if (!inString) {
382+
return inputLine.substring(0, i+1).trimEnd();
383+
}
384+
break;
385+
}
365386
}
366-
367-
return (comment >= 0 ? inputLine.substring(0, comment).trimEnd() : inputLine);
387+
388+
return inputLine;
368389
}
369390

391+
/**
392+
* Removes the trailing comment and optionally removes the semi-colon.
393+
*/
370394
const getValidStatement = (inputLine: string, withSep?: boolean) => {
371-
const comment = inputLine.indexOf(`//`);
372-
const quote = inputLine.lastIndexOf(`'`);
373-
const sep = inputLine.indexOf(`;`, quote >= 0 ? quote : 0);
395+
if (!inputLine.includes(`;`)) return inputLine;
396+
let comment = -1;
397+
let inString = false;
398+
let sep = -1;
399+
for (let i = inputLine.length - 1; i >= 0; i--) {
400+
switch (inputLine[i]) {
401+
case '/':
402+
if (inputLine[i-1] === `/`) {
403+
// It's a comment!
404+
inString = false;
405+
comment = i-1;
406+
i--;
407+
}
408+
break;
409+
case `'`:
410+
inString = !inString;
411+
break;
412+
case ';':
413+
if (!inString) {
414+
sep = i;
415+
break;
416+
}
417+
break;
418+
}
419+
}
374420

375421
if (comment >= 0 && comment < sep) {
376422
return inputLine;

tests/suite/basics.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,4 +1297,27 @@ test(`const keyword check`, async () => {
12971297
const hello = cache.find(`hello`);
12981298
expect(hello.name).toBe(`hello`);
12991299
expect(hello.keyword[`CONST`]).toBe(`556`);
1300+
});
1301+
1302+
test('issue_353_comments', async () => {
1303+
const lines = [
1304+
`**free`,
1305+
`dcl-ds HEDINF based(p1@);`,
1306+
` HRLEN Int(10:0); // Record length`,
1307+
` HCRRN Int(10:0); // Cursor's RRN`,
1308+
` HCPOS Int(10:0); // Cursor's column`,
1309+
` HCCSID Int(10:0); // CCSID of source`,
1310+
` HRECI Int(10:0); // Nbr of input rcds`,
1311+
`end-ds;`,
1312+
`dcl-s p2@ Pointer;`,
1313+
].join(`\n`);
1314+
1315+
const cache = await parser.getDocs(uri, lines, { ignoreCache: true, withIncludes: false });
1316+
1317+
const hedinf = cache.find(`HEDINF`);
1318+
expect(hedinf).toBeDefined();
1319+
console.log(hedinf.subItems.map(s => s.name));
1320+
expect(hedinf.subItems.length).toBe(5);
1321+
const p2at = cache.find(`p2@`);
1322+
expect(p2at).toBeDefined();
13001323
});

tests/suite/linter.test.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3186,4 +3186,87 @@ test('Linter running on member rpgleinc', async () => {
31863186
type: 'SpecificCasing',
31873187
newValue: 'DCL-S'
31883188
});
3189+
});
3190+
3191+
test('issue_353_indent_1', async () => {
3192+
const lines = [
3193+
`**free`,
3194+
`dcl-ds HEDINF based(p1@);`,
3195+
` HRLEN Int(10:0); // Record length`,
3196+
` HCRRN Int(10:0); // Cursor's RRN`,
3197+
` HCPOS Int(10:0); // Cursor's column`,
3198+
` HCCSID Int(10:0); // CCSID of source`,
3199+
` HRECI Int(10:0); // Nbr of input rcds`,
3200+
`end-ds;`,
3201+
`dcl-s p2@ Pointer;`,
3202+
].join(`\n`);
3203+
3204+
const cache = await parser.getDocs(uri, lines, { ignoreCache: true, withIncludes: false });
3205+
3206+
const hedinf = cache.find(`HEDINF`);
3207+
expect(hedinf).toBeDefined();
3208+
expect(hedinf.subItems.length).toBe(5);
3209+
const p2at = cache.find(`p2@`);
3210+
expect(p2at).toBeDefined();
3211+
3212+
const { indentErrors, errors } = Linter.getErrors({ uri, content: lines }, {
3213+
indent: 2
3214+
}, cache);
3215+
3216+
expect(errors.length).toBe(0);
3217+
expect(indentErrors.length).toBe(0);
3218+
});
3219+
3220+
test('issue_353_indent_2', async () => {
3221+
const lines = [
3222+
`**free`,
3223+
`dcl-ds HEDINF based(p1@);`,
3224+
` HRLEN Int(10:0); // Record length`,
3225+
` HCRRN Int(10:0); // Cursor's RRN`,
3226+
` HCPOS Int(10:0); // Cursor's column`,
3227+
` HCCSID Int(10:0); // CCSID of source`,
3228+
` HRECI Int(10:0); // Nbr of input rcds`,
3229+
`end-ds;`,
3230+
`dcl-s p2@ Pointer;`,
3231+
].join(`\n`);
3232+
3233+
const cache = await parser.getDocs(uri, lines, { ignoreCache: true, withIncludes: false });
3234+
3235+
const hedinf = cache.find(`HEDINF`);
3236+
expect(hedinf).toBeDefined();
3237+
expect(hedinf.subItems.length).toBe(5);
3238+
const p2at = cache.find(`p2@`);
3239+
expect(p2at).toBeDefined();
3240+
3241+
const { indentErrors, errors } = Linter.getErrors({ uri, content: lines }, {
3242+
indent: 2
3243+
}, cache);
3244+
3245+
expect(indentErrors.length).toBe(1);
3246+
expect(indentErrors[0]).toMatchObject({
3247+
line: 3,
3248+
expectedIndent: 2,
3249+
currentIndent: 3
3250+
});
3251+
});
3252+
3253+
test('issue_353_indent_3', async () => {
3254+
const lines = [
3255+
`**free`,
3256+
`begsr displayHelp;`,
3257+
` // Do something with this program's`,
3258+
` // name and library ... assume the program is running`,
3259+
` // from the same library as contains the source.`,
3260+
` fileName = 'QRPGLESRC';`,
3261+
` library = pgSts.lib;`,
3262+
`endsr;`,
3263+
].join(`\n`);
3264+
3265+
const cache = await parser.getDocs(uri, lines, { ignoreCache: true, withIncludes: false });
3266+
const { indentErrors, errors } = Linter.getErrors({ uri, content: lines }, {
3267+
indent: 2
3268+
}, cache);
3269+
3270+
expect(errors.length).toBe(0);
3271+
expect(indentErrors.length).toBe(0);
31893272
});

0 commit comments

Comments
 (0)