tree-sitter-delphi13-pure 1.1.0 → 1.2.1

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,26 @@ 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],
364
+ // Iter 2026-07-16 (Register as a field name, ported from root):
365
+ // previous field's trailing callconv vs next field's name; `;` vs `:`
366
+ // one token later decides.
367
+ [$.declFieldNoSemi, $.declField],
368
+ [$.declField],
311
369
  // Anonymous record/class types in type position conflict with the
312
370
  // type-declaration form (`type Foo = record ... end;`). Both reach
313
371
  // declClass but at different parser states.
@@ -381,13 +439,29 @@ module.exports = grammar({
381
439
 
382
440
  rules: {
383
441
  root: $ => optional(choice(
384
- $.program,
385
- $.library,
386
- $.unit,
387
- $.package,
442
+ seq(
443
+ choice(
444
+ $.program,
445
+ $.library,
446
+ $.unit,
447
+ $.package,
448
+ ),
449
+ // Iter 2026-07-16 (ported from root): dcc ignores everything
450
+ // after the final `end.` (warning W1011 only). One
451
+ // low-precedence catch-all token; linters can flag the node.
452
+ optional($.trailingText),
453
+ ),
388
454
  $._definitions // For include files
389
455
  )),
390
456
 
457
+ // Everything from the first non-blank char after the module's final
458
+ // `end.` to EOF. token(prec(-2)) so real tokens (incl. comments)
459
+ // always win over it.
460
+ // NOTE: `(.|\s)*` rather than `[\s\S]*` — tree-sitter's regex engine
461
+ // compiles the latter to a non-greedy/empty match (token stopped after
462
+ // one char; observed 2026-07-16).
463
+ trailingText: $ => token(prec(-2, /[^\s](.|\s)*/)),
464
+
391
465
  // HIGH LEVEL ----------------------------------------------------------
392
466
 
393
467
  program: $ => seq(
@@ -420,13 +494,32 @@ module.exports = grammar({
420
494
  $.kLibrary, // ported from root v1.1.0
421
495
  )),
422
496
  ';',
497
+ // Unit tail, restructured 2026-07-16 (ported from root, iter:
498
+ // implicit-init): `initialization`/`finalization` moved out of the
499
+ // flat repeat into the kEnd tail arm, plus a mutually-exclusive
500
+ // `tr($,'block')` arm for the Turbo-Pascal implicit initialization
501
+ // block (`begin <stmts> end.` — dcc 13 still accepts it). Because
502
+ // the block arm is unreachable once `initialization` appears, the
503
+ // statement-list fork the old shape suffered cannot arise; the only
504
+ // fork is blockTr-inside-_definitions (prec -1 recovery) vs
505
+ // blockTr-as-unit-tail (prec 0), same as `library`. Requires the
506
+ // [$.implementation] conflict. CST: the implicit block renders as
507
+ // the same `block` node `program`/`library` produce.
423
508
  repeat(choice(
424
509
  $.interface,
425
510
  $.implementation,
426
- $.initialization,
427
- $.finalization,
428
511
  )),
429
- $.kEnd, $.kEndDot
512
+ choice(
513
+ seq(
514
+ repeat(choice(
515
+ $.initialization,
516
+ $.finalization,
517
+ )),
518
+ $.kEnd
519
+ ),
520
+ tr($,'block'),
521
+ ),
522
+ $.kEndDot
430
523
  ),
431
524
 
432
525
  // Delphi package file (.dpk). Structure:
@@ -515,6 +608,13 @@ module.exports = grammar({
515
608
  // en/EN not followed by d/D, end immediately followed by ident-char
516
609
  // (so it's NOT the keyword, e.g. 'endif' / 'endloop').
517
610
  asmBody: $ => token(prec(-1, repeat1(choice(
611
+ // Ported from root 2026-07-16: consume a whole COMMENT as one chunk so a
612
+ // bare `end` *inside* a comment doesn't falsely terminate the asm block.
613
+ // add edi,ecx {point EDI to end of destination} <-- AsyncPro AwFView
614
+ // mov eax,1 // end of loop
615
+ // Must precede the single-char alternatives: longest match wins.
616
+ /\{[^}]*\}/,
617
+ /\/\/[^\n]*/,
518
618
  // Identifier not starting with e/E — consume as a unit so an
519
619
  // embedded `end` substring (like in `addend` or `xchg ext`)
520
620
  // doesn't falsely terminate the body.
@@ -753,7 +853,15 @@ module.exports = grammar({
753
853
  typeref: $ => seq(
754
854
  ...enable_if(fpc, field('_dummy', optional($.kSpecialize))),
755
855
  $._typeref,
756
- ...enable_if(delphi, optional(seq($.kDeprecated, $._expr))),
856
+ // Ported from root 2026-07-16: trailing kPlatform hint on the
857
+ // typeref — makes `Default8087CW: Word platform = $033F;`
858
+ // (System.pas x6) parse with declVar's normal defaultValue.
859
+ // Mirrors the existing kDeprecated role-set; the hint-then-value
860
+ // ARM inside declVar is a bisect-confirmed table bomb (TODO.md).
861
+ ...enable_if(delphi, optional(choice(
862
+ seq($.kDeprecated, $._expr),
863
+ $.kPlatform,
864
+ ))),
757
865
  ),
758
866
 
759
867
  _typeref: $ => choice(
@@ -805,8 +913,18 @@ module.exports = grammar({
805
913
  $.identifier, $.genericDot, ...enable_if(templates, $.genericTpl)
806
914
  ),
807
915
  genericArgs: $ => delimited1($.genericArg, ';'),
916
+ // Ported from root 2026-07-16: nested generic instantiation as a
917
+ // genericArg name element (method resolution clause `function
918
+ // TFunc<T1, IEnumerable<TResult>>.Invoke = Bind;`). Self-contained
919
+ // identifier-only recursion — referencing genericTpl/_genericName
920
+ // here explodes table construction.
921
+ genericArgTpl: $ => seq(
922
+ $.identifier, $.kLt,
923
+ delimited1(choice($.identifier, $.genericArgTpl)),
924
+ $.kGt
925
+ ),
808
926
  genericArg: $ => seq(
809
- field('name', delimited1($.identifier)),
927
+ field('name', delimited1(choice($.identifier, $.genericArgTpl))),
810
928
  // Type constraint: `T: BaseType` or one/more of the special
811
929
  // constraint keywords `class` / `record` / `constructor`, comma-
812
930
  // separated. Examples:
@@ -943,7 +1061,11 @@ module.exports = grammar({
943
1061
  ),
944
1062
 
945
1063
  _declarations: $ => repeat1(choice(
946
- $.declTypes, $.declVars, $.declConsts, $.declProc, $.declProp,
1064
+ $.declTypes, $.declVars, $.declConsts,
1065
+ // Lenient directive tail in interface declaration lists (ported
1066
+ // from root); rendered as a plain declProc node.
1067
+ alias($.declProcLenient, $.declProc),
1068
+ $.declProp,
947
1069
  alias($.declProcFwd, $.declProc),
948
1070
  $.declUses, $.declLabels, $.declExports,
949
1071
  // Phase 3 (pure): CIL/.NET [assembly: ...] attributes inside
@@ -1110,6 +1232,12 @@ module.exports = grammar({
1110
1232
  ...enable_if(rtti, optional($.rttiAttributes)),
1111
1233
  choice($._declProc, $._declOperator),
1112
1234
  ),
1235
+ // Interface/forward flavor with the lenient directive tail; aliased
1236
+ // back to `declProc` at its use site (CST-identical).
1237
+ declProcLenient: $ => seq(
1238
+ ...enable_if(rtti, optional($.rttiAttributes)),
1239
+ choice($._declProcLenient, $._declOperator),
1240
+ ),
1113
1241
 
1114
1242
  declVar: $ => seq(
1115
1243
  ...enable_if(rtti, optional($.rttiAttributes)),
@@ -1140,6 +1268,13 @@ module.exports = grammar({
1140
1268
  alias($.kDeprecated, $.identifier),
1141
1269
  alias($.kExperimental, $.identifier),
1142
1270
  alias($.kRegister, $.identifier),
1271
+ // Ported from root 2026-07-16: same family — `local` is a
1272
+ // procAttribute, so `var X: Integer; Local: Integer;` had the
1273
+ // parser eat `Local` as a trailing directive on X.
1274
+ alias($.kLocal, $.identifier),
1275
+ // Ported from root 2026-07-16: `dispid` is a property/method
1276
+ // directive — same trap (System.Win.ObjComAuto, Vcl.OleCtrls).
1277
+ alias($.kDispId, $.identifier),
1143
1278
  ))),
1144
1279
  ':',
1145
1280
  // Phase 3b iter 36: declVar type may be a subrange:
@@ -1405,7 +1540,13 @@ module.exports = grammar({
1405
1540
 
1406
1541
  declField: $ => seq(
1407
1542
  ...enable_if(rtti, optional($.rttiAttributes)),
1408
- field('name', delimited1($.identifier)),
1543
+ // Ported from root 2026-07-16: `Register` as a FIELD NAME after a
1544
+ // prior field (Winapi.D3D10 shader reflection records). Narrow —
1545
+ // only kRegister; see the root note for why not all callconvs.
1546
+ field('name', delimited1(choice(
1547
+ $.identifier,
1548
+ alias($.kRegister, $.identifier),
1549
+ ))),
1409
1550
  ':',
1410
1551
  // Ported from root v1.1.x: field type may be a subrange
1411
1552
  // (`FtrListCount: 0 .. FTRRECMAXCOUNT;`, ORM3 ImportCadFile.pas).
@@ -1500,32 +1641,27 @@ module.exports = grammar({
1500
1641
  // Stuff for procedure / function / operator declarations
1501
1642
 
1502
1643
  _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
- )),
1644
+ ...declProcFront($),
1525
1645
  ';',
1646
+ // STRICT tail — backs defProc, where the `;` before the body is
1647
+ // mandatory. Lenient separator-form twin below (ported from root).
1526
1648
  repeat($._procAttributeNoExt)
1527
1649
  ),
1528
1650
 
1651
+ // Lenient twin for interface declaration lists: directive groups are
1652
+ // `;`-SEPARATED with the final `;` optional, so
1653
+ // `function F: Boolean; overload` before another declaration parses
1654
+ // (dxCryptoAPI, dxServerModeUtils, dxGDIPlusAPI — dcc32-verified).
1655
+ _declProcLenient: $ => seq(
1656
+ ...declProcFront($),
1657
+ ';',
1658
+ optional(seq(
1659
+ repeat1(field('attribute', $.procAttribute)),
1660
+ repeat(seq(';', repeat1(field('attribute', $.procAttribute)))),
1661
+ optional(';')
1662
+ ))
1663
+ ),
1664
+
1529
1665
  _declOperator: $ => seq(
1530
1666
  optional($.kClass),
1531
1667
  $.kOperator,
@@ -1921,7 +2057,10 @@ module.exports = grammar({
1921
2057
  // so structural tokens stay intact.
1922
2058
  identifier: $ => /&{0,2}[a-zA-Z_€-￿][0-9_a-zA-Z€-￿]*/,
1923
2059
 
1924
- _space: $ => /[\s\r\n\t]+/,
2060
+ // Classic Pascal treats every control char <= #31 as a token
2061
+ // separator (dcc compiles sources with stray bytes like the 0x12 in
2062
+ // DevExpress dxPDFForm.pas), so the whitespace extra does too.
2063
+ _space: $ => /[\s\x00-\x1F]+/,
1925
2064
  // Single preprocessor directive. The external scanner (src/scanner.c)
1926
2065
  // handles multi-line `{$IF*}...{$END*}` blocks via the pp_block token,
1927
2066
  // 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.1",
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",