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 +175 -36
- package/package.json +1 -1
- package/src/grammar.json +982 -77
- package/src/node-types.json +83 -0
- package/src/parser.c +391547 -342230
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
|
-
|
|
108
|
-
|
|
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
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
...
|
|
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
|
-
|
|
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
|
|
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",
|