tree-sitter-delphi13-pure 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/grammar.js CHANGED
@@ -104,8 +104,15 @@ function enable_if(cond, ...args) {
104
104
  // Generate rules for trailing & non-trailing statements
105
105
  function statements(trailing) {
106
106
  let rn = x => trailing ? x + 'Tr' : x
107
- let lastStatement = $ => trailing ? optional(tr($,'_statement')) : $._statement;
108
- let lastStatement1= $ => trailing ? tr($,'_statement') : $._statement;
107
+ // Ported from root 2026-07-16: a goto label may prefix the
108
+ // single-statement BODY of then/else/do/on (`if I = 0 then Found: ...`,
109
+ // `else FoundMismatch: Exit`, `while true do redo: case ...`).
110
+ // prec.dynamic(-1) keeps the case-ARM interpretation winning where a
111
+ // label could also open an arm; requires [caseCase]/[caseCaseTr]
112
+ // conflicts.
113
+ let bodyLabel = $ => optional(prec.dynamic(-1, $.label));
114
+ let lastStatement = $ => trailing ? optional(seq(bodyLabel($), tr($,'_statement'))) : seq(bodyLabel($), $._statement);
115
+ let lastStatement1= $ => trailing ? seq(bodyLabel($), tr($,'_statement')) : seq(bodyLabel($), $._statement);
109
116
  let semicolon = trailing ? [] : [';'];
110
117
 
111
118
  return Object.fromEntries([
@@ -272,6 +279,37 @@ function statements(trailing) {
272
279
  ]);
273
280
  }
274
281
 
282
+ // Ported from root 2026-07-16: shared front of a routine declaration
283
+ // (everything before the first `;`) — used by _declProc (strict tail,
284
+ // backs defProc) and _declProcLenient (separator-form tail, interface
285
+ // declaration lists only).
286
+ function declProcFront($) {
287
+ return [
288
+ ...enable_if(fpc, optional($.kGeneric)),
289
+ optional($.kClass),
290
+ choice($.kProcedure, $.kFunction, $.kConstructor, $.kDestructor),
291
+ field('name', $._genericName),
292
+ field('args', optional($.declArgs)),
293
+ optional(seq(
294
+ ':',
295
+ field('type', $.typeref),
296
+ )),
297
+ field('assign', optional($.defaultValue)),
298
+ // Inline calling-convention or procAttribute BEFORE the terminating
299
+ // ';' — Embarcadero RTL / AzureAPI use lenient forms:
300
+ // function DbiInitFn(...): DBIResult stdcall; (iter 56)
301
+ // procedure PreflightBlobRequest(...) overload; (iter 60)
302
+ // `repeat` allows multiple chained attributes like `... cdecl overload`.
303
+ repeat(choice(
304
+ $.kStdcall, $.kCdecl, $.kSafecall, $.kPascal,
305
+ $.kRegister, $.kWinapi, $.kInline,
306
+ $.kOverload, $.kVirtual, $.kAbstract, $.kOverride,
307
+ $.kReintroduce, $.kStatic, $.kDynamic, $.kFinal,
308
+ $.kUnsafe // ARC/AUTOREFCOUNT method directive (ported v1.1.0)
309
+ )),
310
+ ];
311
+ }
312
+
275
313
  module.exports = grammar({
276
314
  name: "delphi13_pure",
277
315
 
@@ -308,6 +346,21 @@ module.exports = grammar({
308
346
  // optional _definitions before AND after declContains. GLR forks
309
347
  // on which slot absorbs a given definition.
310
348
  [$.package],
349
+ // Iter 2026-07-16 (implicit-init, ported from root): the unit tail's
350
+ // `tr($,'block')` arm forks against `implementation` absorbing the
351
+ // same `begin` into its `_definitions` (prec(-1) blockTr recovery).
352
+ // GLR keeps both; precedence picks the unit-tail block.
353
+ [$.implementation],
354
+ // Iter 2026-07-16 (label-as-body, ported from root): body label vs
355
+ // the arm's own jumpLabel slot (`1: Foo: x`); prec.dynamic(-1) keeps
356
+ // the arm interpretation winning.
357
+ [$.caseCase],
358
+ [$.caseCaseTr],
359
+ // Iter 2026-07-16 (lenient directive tail, ported from root): group
360
+ // separator `;` vs optional final `;`, and lenient-tail groups vs
361
+ // declProcFwd's strict groups while both are live.
362
+ [$.procAttribute],
363
+ [$._declProcLenient, $._procAttributeNoExt],
311
364
  // Anonymous record/class types in type position conflict with the
312
365
  // type-declaration form (`type Foo = record ... end;`). Both reach
313
366
  // declClass but at different parser states.
@@ -381,13 +434,29 @@ module.exports = grammar({
381
434
 
382
435
  rules: {
383
436
  root: $ => optional(choice(
384
- $.program,
385
- $.library,
386
- $.unit,
387
- $.package,
437
+ seq(
438
+ choice(
439
+ $.program,
440
+ $.library,
441
+ $.unit,
442
+ $.package,
443
+ ),
444
+ // Iter 2026-07-16 (ported from root): dcc ignores everything
445
+ // after the final `end.` (warning W1011 only). One
446
+ // low-precedence catch-all token; linters can flag the node.
447
+ optional($.trailingText),
448
+ ),
388
449
  $._definitions // For include files
389
450
  )),
390
451
 
452
+ // Everything from the first non-blank char after the module's final
453
+ // `end.` to EOF. token(prec(-2)) so real tokens (incl. comments)
454
+ // always win over it.
455
+ // NOTE: `(.|\s)*` rather than `[\s\S]*` — tree-sitter's regex engine
456
+ // compiles the latter to a non-greedy/empty match (token stopped after
457
+ // one char; observed 2026-07-16).
458
+ trailingText: $ => token(prec(-2, /[^\s](.|\s)*/)),
459
+
391
460
  // HIGH LEVEL ----------------------------------------------------------
392
461
 
393
462
  program: $ => seq(
@@ -420,13 +489,32 @@ module.exports = grammar({
420
489
  $.kLibrary, // ported from root v1.1.0
421
490
  )),
422
491
  ';',
492
+ // Unit tail, restructured 2026-07-16 (ported from root, iter:
493
+ // implicit-init): `initialization`/`finalization` moved out of the
494
+ // flat repeat into the kEnd tail arm, plus a mutually-exclusive
495
+ // `tr($,'block')` arm for the Turbo-Pascal implicit initialization
496
+ // block (`begin <stmts> end.` — dcc 13 still accepts it). Because
497
+ // the block arm is unreachable once `initialization` appears, the
498
+ // statement-list fork the old shape suffered cannot arise; the only
499
+ // fork is blockTr-inside-_definitions (prec -1 recovery) vs
500
+ // blockTr-as-unit-tail (prec 0), same as `library`. Requires the
501
+ // [$.implementation] conflict. CST: the implicit block renders as
502
+ // the same `block` node `program`/`library` produce.
423
503
  repeat(choice(
424
504
  $.interface,
425
505
  $.implementation,
426
- $.initialization,
427
- $.finalization,
428
506
  )),
429
- $.kEnd, $.kEndDot
507
+ choice(
508
+ seq(
509
+ repeat(choice(
510
+ $.initialization,
511
+ $.finalization,
512
+ )),
513
+ $.kEnd
514
+ ),
515
+ tr($,'block'),
516
+ ),
517
+ $.kEndDot
430
518
  ),
431
519
 
432
520
  // Delphi package file (.dpk). Structure:
@@ -515,6 +603,13 @@ module.exports = grammar({
515
603
  // en/EN not followed by d/D, end immediately followed by ident-char
516
604
  // (so it's NOT the keyword, e.g. 'endif' / 'endloop').
517
605
  asmBody: $ => token(prec(-1, repeat1(choice(
606
+ // Ported from root 2026-07-16: consume a whole COMMENT as one chunk so a
607
+ // bare `end` *inside* a comment doesn't falsely terminate the asm block.
608
+ // add edi,ecx {point EDI to end of destination} <-- AsyncPro AwFView
609
+ // mov eax,1 // end of loop
610
+ // Must precede the single-char alternatives: longest match wins.
611
+ /\{[^}]*\}/,
612
+ /\/\/[^\n]*/,
518
613
  // Identifier not starting with e/E — consume as a unit so an
519
614
  // embedded `end` substring (like in `addend` or `xchg ext`)
520
615
  // doesn't falsely terminate the body.
@@ -805,8 +900,18 @@ module.exports = grammar({
805
900
  $.identifier, $.genericDot, ...enable_if(templates, $.genericTpl)
806
901
  ),
807
902
  genericArgs: $ => delimited1($.genericArg, ';'),
903
+ // Ported from root 2026-07-16: nested generic instantiation as a
904
+ // genericArg name element (method resolution clause `function
905
+ // TFunc<T1, IEnumerable<TResult>>.Invoke = Bind;`). Self-contained
906
+ // identifier-only recursion — referencing genericTpl/_genericName
907
+ // here explodes table construction.
908
+ genericArgTpl: $ => seq(
909
+ $.identifier, $.kLt,
910
+ delimited1(choice($.identifier, $.genericArgTpl)),
911
+ $.kGt
912
+ ),
808
913
  genericArg: $ => seq(
809
- field('name', delimited1($.identifier)),
914
+ field('name', delimited1(choice($.identifier, $.genericArgTpl))),
810
915
  // Type constraint: `T: BaseType` or one/more of the special
811
916
  // constraint keywords `class` / `record` / `constructor`, comma-
812
917
  // separated. Examples:
@@ -943,7 +1048,11 @@ module.exports = grammar({
943
1048
  ),
944
1049
 
945
1050
  _declarations: $ => repeat1(choice(
946
- $.declTypes, $.declVars, $.declConsts, $.declProc, $.declProp,
1051
+ $.declTypes, $.declVars, $.declConsts,
1052
+ // Lenient directive tail in interface declaration lists (ported
1053
+ // from root); rendered as a plain declProc node.
1054
+ alias($.declProcLenient, $.declProc),
1055
+ $.declProp,
947
1056
  alias($.declProcFwd, $.declProc),
948
1057
  $.declUses, $.declLabels, $.declExports,
949
1058
  // Phase 3 (pure): CIL/.NET [assembly: ...] attributes inside
@@ -1110,6 +1219,12 @@ module.exports = grammar({
1110
1219
  ...enable_if(rtti, optional($.rttiAttributes)),
1111
1220
  choice($._declProc, $._declOperator),
1112
1221
  ),
1222
+ // Interface/forward flavor with the lenient directive tail; aliased
1223
+ // back to `declProc` at its use site (CST-identical).
1224
+ declProcLenient: $ => seq(
1225
+ ...enable_if(rtti, optional($.rttiAttributes)),
1226
+ choice($._declProcLenient, $._declOperator),
1227
+ ),
1113
1228
 
1114
1229
  declVar: $ => seq(
1115
1230
  ...enable_if(rtti, optional($.rttiAttributes)),
@@ -1140,6 +1255,13 @@ module.exports = grammar({
1140
1255
  alias($.kDeprecated, $.identifier),
1141
1256
  alias($.kExperimental, $.identifier),
1142
1257
  alias($.kRegister, $.identifier),
1258
+ // Ported from root 2026-07-16: same family — `local` is a
1259
+ // procAttribute, so `var X: Integer; Local: Integer;` had the
1260
+ // parser eat `Local` as a trailing directive on X.
1261
+ alias($.kLocal, $.identifier),
1262
+ // Ported from root 2026-07-16: `dispid` is a property/method
1263
+ // directive — same trap (System.Win.ObjComAuto, Vcl.OleCtrls).
1264
+ alias($.kDispId, $.identifier),
1143
1265
  ))),
1144
1266
  ':',
1145
1267
  // Phase 3b iter 36: declVar type may be a subrange:
@@ -1500,32 +1622,27 @@ module.exports = grammar({
1500
1622
  // Stuff for procedure / function / operator declarations
1501
1623
 
1502
1624
  _declProc: $ => seq(
1503
- ...enable_if(fpc, optional($.kGeneric)),
1504
- optional($.kClass),
1505
- choice($.kProcedure, $.kFunction, $.kConstructor, $.kDestructor),
1506
- field('name', $._genericName),
1507
- field('args', optional($.declArgs)),
1508
- optional(seq(
1509
- ':',
1510
- field('type', $.typeref),
1511
- )),
1512
- field('assign', optional($.defaultValue)),
1513
- // Inline calling-convention or procAttribute BEFORE the terminating
1514
- // ';' — Embarcadero RTL / AzureAPI use lenient forms:
1515
- // function DbiInitFn(...): DBIResult stdcall; (iter 56)
1516
- // procedure PreflightBlobRequest(...) overload; (iter 60)
1517
- // `repeat` allows multiple chained attributes like `... cdecl overload`.
1518
- repeat(choice(
1519
- $.kStdcall, $.kCdecl, $.kSafecall, $.kPascal,
1520
- $.kRegister, $.kWinapi, $.kInline,
1521
- $.kOverload, $.kVirtual, $.kAbstract, $.kOverride,
1522
- $.kReintroduce, $.kStatic, $.kDynamic, $.kFinal,
1523
- $.kUnsafe // ARC/AUTOREFCOUNT method directive (ported v1.1.0)
1524
- )),
1625
+ ...declProcFront($),
1525
1626
  ';',
1627
+ // STRICT tail — backs defProc, where the `;` before the body is
1628
+ // mandatory. Lenient separator-form twin below (ported from root).
1526
1629
  repeat($._procAttributeNoExt)
1527
1630
  ),
1528
1631
 
1632
+ // Lenient twin for interface declaration lists: directive groups are
1633
+ // `;`-SEPARATED with the final `;` optional, so
1634
+ // `function F: Boolean; overload` before another declaration parses
1635
+ // (dxCryptoAPI, dxServerModeUtils, dxGDIPlusAPI — dcc32-verified).
1636
+ _declProcLenient: $ => seq(
1637
+ ...declProcFront($),
1638
+ ';',
1639
+ optional(seq(
1640
+ repeat1(field('attribute', $.procAttribute)),
1641
+ repeat(seq(';', repeat1(field('attribute', $.procAttribute)))),
1642
+ optional(';')
1643
+ ))
1644
+ ),
1645
+
1529
1646
  _declOperator: $ => seq(
1530
1647
  optional($.kClass),
1531
1648
  $.kOperator,
@@ -1921,7 +2038,10 @@ module.exports = grammar({
1921
2038
  // so structural tokens stay intact.
1922
2039
  identifier: $ => /&{0,2}[a-zA-Z_€-￿][0-9_a-zA-Z€-￿]*/,
1923
2040
 
1924
- _space: $ => /[\s\r\n\t]+/,
2041
+ // Classic Pascal treats every control char <= #31 as a token
2042
+ // separator (dcc compiles sources with stray bytes like the 0x12 in
2043
+ // DevExpress dxPDFForm.pas), so the whitespace extra does too.
2044
+ _space: $ => /[\s\x00-\x1F]+/,
1925
2045
  // Single preprocessor directive. The external scanner (src/scanner.c)
1926
2046
  // handles multi-line `{$IF*}...{$END*}` blocks via the pp_block token,
1927
2047
  // refusing blocks that wrap structural decls so they parse normally.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tree-sitter-delphi13-pure",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Pure Delphi 13 tree-sitter sub-grammar — drops {$IFDEF}/pp_* tokens entirely and expects preprocessor-resolved source as input. Pairs with delphi13-preprocessor to reach 99%+ pass on real Delphi 13 corpora.",
5
5
  "main": "bindings/node",
6
6
  "types": "bindings/node",