Skip to content

Commit cb49d3f

Browse files
nixel2007claude
andcommitted
Close comma-skipping and multi-line-string-with-blank-rows gaps
Two changes that take the real-world parse rate to 92% / 100% (bsl-language-server / vsc-language-1c-bsl fixtures), with only four remaining degraded files in the lsl set — all of them intentionally malformed (*ParseError* tests, or genuine source typos like 'Неопределенно' / 'Функция Пример3' without parens). 1. Argument lists model empty slots as actual callArgs, mirroring ANTLR's 'callParamList : callParam (COMMA callParam)*' / 'callParam : expression?' pair. Since Lezer doesn't accept literally empty productions, the empty branch is expressed as a '~callArgEmpty' ambig-marked alternative inside 'callArg'; the with-expression alternative carries '@dynamicPrecedence=1' so the GLR engine prefers consuming the expression whenever one is available (so 'f(g(x))' still parses as a single nested call, not as 'f' applied to 'g' and '(x)' separately). '()' / '(a)' / '(a, b)' / '(, a)' / '(a, )' / '(a, , b)' / '(, , )' now all parse cleanly. 2. The multi-line String token allows blank rows between '|'-continued segments. The previous regex required exactly one newline before each continuation marker, so a query body broken across paragraphs (rather common in real configs — and also the literal test input that QueryComputerDateTimeTest reproduces, with its 20+ blank rows triggering StringIndexOutOfBoundsException upstream) was an error token. Changing '$[\n\r]' to '$[\n\r]+' tolerates an arbitrary run. Sample-set numbers before → after: bsl-language-server: 88% → 92% (+2 files clean) vsc-language-1c-bsl: 88% → 100% (+2 files clean) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent e320878 commit cb49d3f

1 file changed

Lines changed: 25 additions & 9 deletions

File tree

src/bsl.grammar

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -299,13 +299,26 @@ dotKeyword {
299299
}
300300
IndexAccess { LBrack expression RBrack }
301301

302-
// Argument list — comma-skipping (`Метод(a,,b)` / `Метод(,a)`) is not
303-
// supported. Removed the failed attempt to model `,` as a stand-alone item;
304-
// it fundamentally collides with `f(g(...))` inner-call parsing in LR(1).
305-
// See README → Limitations for context.
306-
callArgs { LParen callArgsList? RParen }
302+
// Argument lists allow trailing/leading/skipped arguments. Mirrors ANTLR's
303+
// `callParamList : callParam (COMMA callParam)*` / `callParam : expression?`
304+
// — empty slots are real parser positions, not just "missing tokens".
305+
// `@dynamicPrecedence=1` on the with-expression alternative tells Lezer's
306+
// GLR engine to prefer the parse that includes the expression over an
307+
// empty callArg at every choice point.
308+
// callArg can be EMPTY (the `~callArgEmpty` marker stands in for ANTLR's
309+
// `callParam : expression?` empty branch — Lezer doesn't accept literally
310+
// empty productions, so an ambig-marked alternative carries the same
311+
// meaning). `()`, `(a)`, `(a, b)`, `(, a)`, `(a, , b)` all roll into the
312+
// same shape: `callArgsList` is always present, the empty slots show up
313+
// as bare `callArg` nodes with no `expression` child.
314+
callArgs { LParen callArgsList RParen }
307315
callArgsList { callArg (Comma callArg)* }
308-
callArg { expression }
316+
callArg {
317+
callArgEmpty |
318+
callArgValue
319+
}
320+
callArgEmpty { ~callArgEmpty }
321+
callArgValue[@dynamicPrecedence=1] { expression }
309322

310323
TernaryOp { Question LParen expression Comma expression Comma expression RParen }
311324
NewExpr { New (Identifier callArgs? | callArgs) }
@@ -427,11 +440,14 @@ preprocBoolOp { Or | And }
427440
// Numeric literals.
428441
Number { $[0-9]+ ("." $[0-9]*)? }
429442

430-
// String literal — both single-line and multi-line. Multi-line continuation:
431-
// newline, optional whitespace, vertical bar `|`, then more content.
443+
// String literal — both single-line and multi-line. Multi-line
444+
// continuation: one or more newlines (so blank lines between segments are
445+
// tolerated, mirroring how ANTLR's token-stream STRINGPART approach lets
446+
// blank rows fall on the HIDDEN channel), optional indentation, the
447+
// vertical bar `|`, then more content.
432448
String {
433449
'"' (![\n\r"] | '""')*
434-
($[\n\r] $[ \t]* "|" (![\n\r"] | '""')*)*
450+
($[\n\r]+ $[ \t]* "|" (![\n\r"] | '""')*)*
435451
'"'
436452
}
437453

0 commit comments

Comments
 (0)