Skip to content

Commit 97ecfe7

Browse files
DeusDataouzsrcm
andcommitted
feat(lang): add Oracle PL/SQL support (distilled from DeusData#1033)
Vendor AndreasMaierDe/tree-sitter-plsql @ 28aebef209be (MIT, ABI 14, no external scanner) and wire CBM_LANG_PLSQL end to end: - extraction onto existing labels only: package spec/body -> Class, procedure/function (create/definition/declaration) -> Function, file -> Module; callee extraction for ref_call incl. the package-qualified pkg.name form; identifier usage vocabulary with the upstream 'parameter' kind (a ref_call ARGUMENT wrapper) carved out of the whole-binding rule - discover: .pks/.pkb/.pck/.pls/.plb/.plsql/.fnc/.trg/.bdy/.tps/.tpb (.sql stays SQL and .prc stays FORM, both asserted negatively) - ledgers: CALL_WITHOUT_REFERENCE_VOCAB(PLSQL), call-node manifest ref_call row (historical total 219 -> 220), call-argument matrix B row - tests: extraction triple (package body + package-qualified call, standalone function, honest negative pin of the upstream CREATE TYPE ... AS OBJECT ERROR-node limitation), grammar-regression case, label golden Class:1,Function:1,Module:1, MUST_EXTRACT_DEFS, extension mapping, bug-repro board battery row - MANIFEST.md (community-niche verdict, local include-quote patch row), THIRD_PARTY.md section, refreshed vendored checksums PL/SQL support was contributed by Oguz (@ouzsrcm) in DeusData#1033; re-vendored from upstream per vendoring policy with his language wiring distilled on top. Co-authored-by: Oğuz <oguzhan.saricam@gmail.com> Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
1 parent 3cda5b1 commit 97ecfe7

25 files changed

Lines changed: 354331 additions & 19 deletions

‎THIRD_PARTY.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,21 @@ License summary:
6464
base, MIT, (c) 2014 Max Brunsfeld) with (c) 2026 DeusData ArkTS additions;
6565
its grammar source lives in `tools/tree-sitter-arkts/`.
6666

67+
### tree-sitter-plsql
68+
69+
- **Project:** [AndreasMaierDe/tree-sitter-plsql](https://github.com/AndreasMaierDe/tree-sitter-plsql)
70+
- **License:** MIT
71+
- **Copyright:** (c) 2022 AndreasMaierDe
72+
- **Vendored at:** `internal/cbm/vendored/grammars/plsql/`
73+
- **Pinned commit:** `28aebef209be`
74+
- **Notes:** Community-maintained grammar for Oracle PL/SQL; not in the
75+
nvim-treesitter or Helix registries (`community-niche` in the manifest). No
76+
external scanner. One local patch: `parser.c`'s
77+
`#include <tree_sitter/parser.h>` is changed to the quoted form used by every
78+
other vendored grammar, as documented in
79+
`internal/cbm/vendored/grammars/MANIFEST.md`. PL/SQL support was originally
80+
contributed in PR #1033 by Oğuz (@ouzsrcm).
81+
6782
### tree-sitter-objectscript (UDL + routine)
6883

6984
- **Project:** [intersystems/tree-sitter-objectscript](https://github.com/intersystems/tree-sitter-objectscript)

‎internal/cbm/cbm.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ typedef enum {
175175
CBM_LANG_OBJECTSCRIPT_ROUTINE, // InterSystems ObjectScript routine (.mac/.int/.rtn/.inc)
176176
CBM_LANG_OBJECTSCRIPT_EXPORT, // InterSystems Studio Export XML (<Export generator="Cache">)
177177
CBM_LANG_ARKTS, // ArkTS (HarmonyOS/OpenHarmony .ets — TypeScript superset + ArkUI)
178+
CBM_LANG_PLSQL, // Oracle PL/SQL
178179
CBM_LANG_COUNT
179180
} CBMLanguage;
180181

‎internal/cbm/extract_calls.c‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,32 @@ static char *extract_ada_callee(CBMArena *a, TSNode node, const char *source, co
826826
return NULL;
827827
}
828828

829+
/* PL/SQL: ref_call → referenced_element. Package-qualified calls use
830+
* ref_name_parent.ref_name (e.g. UTIL_PKG.CALC_SALARY); bare calls use
831+
* ref_name alone. */
832+
static char *extract_plsql_callee(CBMArena *a, TSNode node, const char *source, const char *nk) {
833+
if (strcmp(nk, "ref_call") != 0) {
834+
return NULL;
835+
}
836+
TSNode ref = cbm_find_child_by_kind(node, "referenced_element");
837+
if (ts_node_is_null(ref)) {
838+
return NULL;
839+
}
840+
TSNode parent = ts_node_child_by_field_name(ref, TS_FIELD("ref_name_parent"));
841+
TSNode name = ts_node_child_by_field_name(ref, TS_FIELD("ref_name"));
842+
if (!ts_node_is_null(parent) && !ts_node_is_null(name)) {
843+
char *p = cbm_node_text(a, parent, source);
844+
char *n = cbm_node_text(a, name, source);
845+
if (p && n && p[0] && n[0]) {
846+
return cbm_arena_sprintf(a, "%s.%s", p, n);
847+
}
848+
}
849+
if (!ts_node_is_null(name)) {
850+
return cbm_node_text(a, name, source);
851+
}
852+
return cbm_node_text(a, ref, source);
853+
}
854+
829855
// Solidity: a call_expression's callee is on the `function` field, wrapped in an
830856
// `expression` node (call_expression -> function:expression -> identifier). Descend
831857
// left-most through expression wrappers until we reach the identifier/member.
@@ -1369,6 +1395,9 @@ static char *extract_callee_lang_specific(CBMArena *a, TSNode node, const char *
13691395
if (lang == CBM_LANG_ADA) {
13701396
return extract_ada_callee(a, node, source, nk);
13711397
}
1398+
if (lang == CBM_LANG_PLSQL) {
1399+
return extract_plsql_callee(a, node, source, nk);
1400+
}
13721401
if (lang == CBM_LANG_SOLIDITY) {
13731402
return extract_solidity_callee(a, node, source, nk);
13741403
}

‎internal/cbm/extract_defs.c‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,18 @@ TSNode cbm_resolve_func_name(TSNode node, CBMLanguage lang) {
10511051
}
10521052
}
10531053

1054+
/* PL/SQL: create_function / create_procedure / function_* / procedure_*
1055+
* carry fnc_name / prc_name, not the generic name field. */
1056+
if (lang == CBM_LANG_PLSQL) {
1057+
TSNode nm = ts_node_child_by_field_name(node, TS_FIELD("fnc_name"));
1058+
if (ts_node_is_null(nm)) {
1059+
nm = ts_node_child_by_field_name(node, TS_FIELD("prc_name"));
1060+
}
1061+
if (!ts_node_is_null(nm)) {
1062+
return nm;
1063+
}
1064+
}
1065+
10541066
/* Smali (no `name` field): method_definition > method_signature >
10551067
* method_identifier holds the method name. */
10561068
if (lang == CBM_LANG_SMALI && strcmp(kind, "method_definition") == 0) {
@@ -4255,6 +4267,16 @@ static void extract_class_def(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec
42554267
name_node = ts_node_child_by_field_name(node, TS_FIELD("type"));
42564268
}
42574269
}
4270+
// PL/SQL: package / type / trigger names use dedicated fields, not `name`.
4271+
if (ts_node_is_null(name_node) && ctx->language == CBM_LANG_PLSQL) {
4272+
name_node = ts_node_child_by_field_name(node, TS_FIELD("package_name"));
4273+
if (ts_node_is_null(name_node)) {
4274+
name_node = ts_node_child_by_field_name(node, TS_FIELD("type_name"));
4275+
}
4276+
if (ts_node_is_null(name_node)) {
4277+
name_node = ts_node_child_by_field_name(node, TS_FIELD("trigger_name"));
4278+
}
4279+
}
42584280
// Verilog/SystemVerilog (FIELD_COUNT 0): module/class/interface/package use a
42594281
// nested simple_identifier (first descendant); type_declaration must use the
42604282
// DIRECT-child simple_identifier (member/enum idents precede the typedef name).

‎internal/cbm/extract_usages.c‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ static bool is_reference_node(TSNode node, CBMLanguage lang) {
197197
case CBM_LANG_OBJECTSCRIPT_ROUTINE:
198198
return strcmp(kind, "objectscript_identifier") == 0 ||
199199
strcmp(kind, "objectscript_identifier_special") == 0;
200+
case CBM_LANG_PLSQL:
201+
return strcmp(kind, "identifier") == 0;
200202
default:
201203
return false;
202204
}
@@ -1097,6 +1099,14 @@ static bool is_binding_occurrence(CBMExtractCtx *ctx, TSNode node, const CBMLang
10971099
}
10981100

10991101
const char *kind = ts_node_type(parent);
1102+
/* PL/SQL: `parameter` is a ref_call ARGUMENT wrapper (upstream grammar
1103+
* naming), not a declaration; definition-side bindings use the distinct
1104+
* parameter_declaration kind. Skip it so call arguments stay ordinary
1105+
* value usages. */
1106+
if (ctx->language == CBM_LANG_PLSQL && strcmp(kind, "parameter") == 0) {
1107+
current = parent;
1108+
continue;
1109+
}
11001110
if (kind_in_exact_set(kind, common_whole_binding_nodes) ||
11011111
kind_in_exact_set(kind, occurrence->whole_binding_nodes)) {
11021112
return true;

‎internal/cbm/grammar_plsql.c‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Vendored tree-sitter grammar: plsql (Oracle PL/SQL — AndreasMaierDe/tree-sitter-plsql)
2+
// Each grammar compiled as separate unit (conflicting static symbols).
3+
#include "vendored/grammars/plsql/parser.c"

‎internal/cbm/lang_specs.c‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ extern const TSLanguage *tree_sitter_mojo(void);
168168
extern const TSLanguage *tree_sitter_objectscript_udl(void);
169169
extern const TSLanguage *tree_sitter_objectscript_routine(void);
170170
extern const TSLanguage *tree_sitter_arkts(void);
171+
extern const TSLanguage *tree_sitter_plsql(void);
171172

172173
// -- Empty sentinel --
173174
static const char *empty_types[] = {NULL};
@@ -1635,6 +1636,29 @@ static const char *mojo_branch_types[] = {"if_statement",
16351636
static const char *mojo_var_types[] = {"assignment", NULL};
16361637
static const char *mojo_assign_types[] = {"assignment", "augmented_assignment", NULL};
16371638

1639+
// ==================== PL/SQL ====================
1640+
// Node names verified against AndreasMaierDe/tree-sitter-plsql grammar.js.
1641+
static const char *plsql_func_types[] = {"create_function",
1642+
"create_procedure",
1643+
"function_definition",
1644+
"procedure_definition",
1645+
"function_declaration",
1646+
"procedure_declaration",
1647+
NULL};
1648+
static const char *plsql_class_types[] = {"create_package", "create_package_body", "create_type",
1649+
"create_type_body", "create_trigger", NULL};
1650+
static const char *plsql_module_types[] = {"source_file", NULL};
1651+
static const char *plsql_call_types[] = {"ref_call", NULL};
1652+
static const char *plsql_branch_types[] = {"if_statement",
1653+
"case_statement",
1654+
"basic_loop_statement",
1655+
"for_loop_statement",
1656+
"while_loop_statement",
1657+
"exception_handler",
1658+
NULL};
1659+
static const char *plsql_assign_types[] = {"assignment_statement", NULL};
1660+
static const char *plsql_throw_types[] = {"raise_statement", NULL};
1661+
16381662
// InterSystems ObjectScript. Node names verified against
16391663
// intersystems/tree-sitter-objectscript grammar.
16401664
static const char *objectscript_udl_func_types[] = {"method", "classmethod", "query", NULL};
@@ -2666,6 +2690,11 @@ static const CBMLangSpec lang_specs[CBM_LANG_COUNT] = {
26662690
NULL},
26672691
js_throw_types, NULL, ts_decorator_types, NULL,
26682692
ts_env_members, tree_sitter_arkts, NULL},
2693+
// CBM_LANG_PLSQL — Oracle PL/SQL. AndreasMaierDe/tree-sitter-plsql (MIT).
2694+
[CBM_LANG_PLSQL] = {CBM_LANG_PLSQL, plsql_func_types, plsql_class_types, empty_types,
2695+
plsql_module_types, plsql_call_types, empty_types, empty_types,
2696+
plsql_branch_types, empty_types, plsql_assign_types, plsql_throw_types,
2697+
NULL, empty_types, NULL, NULL, tree_sitter_plsql, NULL},
26692698

26702699
};
26712700

‎internal/cbm/vendored/grammars/MANIFEST.md‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ The grammars were originally vendored as bare `parser.c`+`scanner.c` with **no r
99

1010
## Summary
1111

12-
- Grammars: **160** — vendored-from-upstream: **142**, first-party/self-maintained: **13**, registry-disagreement: **5** (nim removed 2026-06-12; objectscript_udl + objectscript_routine added 2026-06-24; mojo added 2026-07-01; arkts added 2026-08-26 — see notes below)
13-
- ABI distribution: **7×** ABI-13 **85×** ABI-14 **65×** ABI-15 (runtime ceiling is ABI 15; never vendor ABI 16 without a runtime upgrade)
12+
- Grammars: **161** — vendored-from-upstream: **143**, first-party/self-maintained: **13**, registry-disagreement: **5** (nim removed 2026-06-12; objectscript_udl + objectscript_routine added 2026-06-24; mojo added 2026-07-01; arkts added 2026-08-26; plsql added 2026-08-27 — see notes below)
13+
- ABI distribution: **7×** ABI-13 **86×** ABI-14 **65×** ABI-15 (runtime ceiling is ABI 15; never vendor ABI 16 without a runtime upgrade)
1414
- Vendored copies missing LICENSE: **0** — all upstream LICENSE files restored 2026-06-11 (first-party grammars carry the project MIT license; `move` uses the Helix-listed upstream tzakian/tree-sitter-move MIT text, `zsh` uses georgeharker/tree-sitter-zsh MIT)
15-
- `verdict`: VERIFIED-BOTH = our source matches *both* registries; VERIFIED-NVIM/HELIX = matches one; registry-disagreement = registries name a different repo (listed separately); `vendor-maintained` = the language vendor's own grammar, not in nvim/Helix.
15+
- `verdict`: VERIFIED-BOTH = our source matches *both* registries; VERIFIED-NVIM/HELIX = matches one; registry-disagreement = registries name a different repo (listed separately); `vendor-maintained` = the language vendor's own grammar, not in nvim/Helix; `community-niche` = an individual/community-maintained grammar for a niche language, not in nvim/Helix — provenance hand-verified against the upstream repository instead of a registry.
1616
- **objectscript_udl / objectscript_routine** (added 2026-06-24): vendored from [intersystems/tree-sitter-objectscript](https://github.com/intersystems/tree-sitter-objectscript) @ `a7ffcdf` — MIT, the InterSystems-official grammars (a niche vendor language, hence `vendor-maintained`, not in nvim-treesitter/Helix). **Re-vendor note:** each `scanner.c`'s upstream `#include "../../common/scanner.h"` is repointed to a per-directory `objectscript_common.h` (a verbatim copy of upstream `common/scanner.h`), because this repo's shared `vendored/common/scanner.h` belongs to the cfml/fsharp grammars and differs. The generated `parser.c`/`scanner.c` are otherwise byte-for-byte upstream — on re-vendor, re-apply only that single include rename. **Local modification (2026-07-16):** in `objectscript_common.h`, two loop counters `uint8_t i` were widened to `int i` (the `reverse_marker` scan and the `html_marker_buffer` reversal) to clear CodeQL `cpp/comparison-with-wider-type` — a false positive in practice (both lengths are hard-bounded by `MARKER_BUFFER_MAX_LEN = 30`, so `uint8_t` could never wrap), fixed for cleanliness. On re-vendor, re-apply this widening too (or upstream it at intersystems/tree-sitter-objectscript).
1717
- **mojo** (added 2026-07-01): vendored from [lsh/tree-sitter-mojo](https://github.com/lsh/tree-sitter-mojo) @ `33193a99afe6` — MIT, ABI 15. Helix tracks `lsh/tree-sitter-mojo` as its Mojo grammar source, but the Helix-pinned commit (`3d7c53b8038f`) no longer resolves in the upstream repository after a force-push, so this vendor uses current upstream `main` rather than the stale registry SHA. Security review covered only the vendored C surface (`parser.c`, `scanner.c`, `tree_sitter/*.h`) plus upstream license/provenance metadata; no package manager hooks, workflow files, prompt/agent instruction files, or generated lockfiles were vendored.
1818
- **arkts** (added 2026-08-26): **first-party derivative** — a fork of [tree-sitter/tree-sitter-typescript](https://github.com/tree-sitter/tree-sitter-typescript)'s `typescript` dialect pinned @ `75b3874edb2d` (v0.23.2, the same commit our vendored typescript/tsx come from), on the tree-sitter-javascript base @ `3a837b6f3658` (v0.23.1, the version upstream's own package-lock pins), extended with ArkTS/ArkUI syntax (`@Component struct` declarations, UI-DSL trailing-closure calls with post-block attribute chains, decorated function declarations, `import lazy`, `@Extend`/`@Styles` leading-dot attribute chains, anonymous `stateStyles` style blocks). Grammar source + corpus tests live in `tools/tree-sitter-arkts/`; regenerate with `npx tree-sitter-cli@0.25.10 generate` (ABI 15). **External scanner:** `scanner.c` is a symbol-rename trampoline; `_common_scanner.h` is byte-identical (same SHA-256) to the reviewed `typescript/_common_scanner.h` already shipped. **LICENSE:** tree-sitter-typescript's MIT text **verbatim and byte-identical** (© 2017 Max Brunsfeld) — which is what MIT requires of a derivative work, and what lets the provenance audit byte-verify it against upstream rather than take a note on trust. The fork is registered in the audit's `FORKS` map. Our own copyright for the ArkTS additions, and the tree-sitter-javascript attribution (© 2014 Max Brunsfeld), live with the SOURCE in `tools/tree-sitter-arkts/grammar.js` and in `THIRD_PARTY.md`, which is what ships in the release archives.
19+
- **plsql** (added 2026-08-27): vendored from [AndreasMaierDe/tree-sitter-plsql](https://github.com/AndreasMaierDe/tree-sitter-plsql) @ `28aebef209be` (full: `28aebef209be57169600e1aa41ca1431cc6c916f`, upstream tip; repo dormant since 2023-02) — MIT, ABI 14, **no external scanner** (`EXTERNAL_TOKEN_COUNT 0`). Not listed in nvim-treesitter/Helix (`community-niche`, an individual-maintained grammar); provenance verified directly against upstream (pin = `git ls-remote` HEAD; vendored `parser.c` byte-identical to the pinned clone apart from the include-quote local patch below; 0 non-ASCII bytes; 0 dangerous calls). Security review covered only the vendored C surface (`parser.c`, `tree_sitter/parser.h`) plus upstream license/provenance metadata; no package manager hooks, workflow files, prompt/agent instruction files, or generated lockfiles were vendored. Known upstream limitation: `CREATE TYPE ... AS OBJECT` currently yields ERROR nodes (pinned by `plsql_create_type_as_object_limitation` in `tests/test_extraction.c` + `tests/fixtures/plsql/create_type_as_object_limitation.tps`). Originally contributed as PR #1033 by Oğuz (@ouzsrcm); re-vendored from upstream per vendoring policy with the PR's language wiring distilled on top.
1920

2021
> ⚠️ **Pinned commit = the revision nvim-treesitter/Helix vendor** (battle-tested, canonical source), not bleeding-edge HEAD. When re-vendoring, update the pinned commit here.
2122
@@ -46,6 +47,7 @@ Guarded by the `contract_all_grammars_in_graph` graph-breadth test in
4647
| ispc | added to the C-family declarator-name gate (extends tree-sitter-c) |
4748
| odin | `resolve_func_name`: `procedure_declaration` → `identifier` child |
4849
| pascal | `resolve_func_name`: `defProc` → `header` (`declProc`) child's `name` field |
50+
| plsql | `resolve_func_name`: `fnc_name`/`prc_name` fields; `extract_class_def`: `package_name`/`type_name`/`trigger_name` fields; `extract_plsql_callee` (extract_calls.c): `ref_call` → `referenced_element`, package-qualified `ref_name_parent.ref_name`; usage vocabulary (extract_usages.c): `identifier`, with the upstream `parameter` kind (a ref_call ARGUMENT wrapper) carved out of the whole-binding rule |
4951
| racket | `extract_lisp_def`: `(define …)` head-symbol forms in `list` |
5052
| rescript | `resolve_func_name`: `function` (arrow) → enclosing `let_binding`'s `pattern` field |
5153
| scheme | `extract_lisp_def`: `(define …)` head-symbol forms in `list` |
@@ -54,7 +56,7 @@ Guarded by the `contract_all_grammars_in_graph` graph-breadth test in
5456

5557
## Local source patches (applied atop pinned upstream)
5658

57-
The grammars below carry a small local patch to their vendored `scanner.c`, on
59+
The grammars below carry a small local patch to their vendored sources, on
5860
top of the pinned upstream commit recorded in the vendoring table below.
5961
Re-vendoring from upstream must re-apply these.
6062

@@ -63,6 +65,7 @@ Re-vendoring from upstream must re-apply these.
6365
| crystal | `crystal/scanner.c`, serialize | guard `memcpy(&buffer[offset], state->literals.contents, literal_content_size)` with `if (literal_content_size > 0)` | UBSan: zero-length `memcpy` with a NULL/0-size source on the empty-state serialize round-trip (formal UB, harmless) |
6466
| rescript | `rescript/scanner.c`, deserialize | guard `memcpy(state, buffer, n_bytes)` with `if (n_bytes > 0)` | UBSan: zero-length `memcpy` with a NULL `buffer` / `n_bytes == 0` on empty-state deserialize (formal UB, harmless). The sibling serialize copies a fixed `sizeof(ScannerState)` (always > 0, non-NULL src) and needs no guard. |
6567
| purescript | `purescript/scanner.c`, serialize | guard `memcpy(buffer, indents->data, to_copy)` with `if (to_copy > 0)` | UBSan: zero-length `memcpy` with a NULL/0-size source when the indent vector is empty (formal UB, harmless) |
68+
| plsql | `plsql/parser.c`, include | `#include <tree_sitter/parser.h>` → `#include "tree_sitter/parser.h"` | The older ABI-14 generator emits angle brackets; every other vendored grammar uses the quoted form, which resolves the per-grammar `tree_sitter/` header from the including file's directory |
6669

6770
## Vendored from verified upstream
6871

@@ -158,6 +161,7 @@ Re-vendoring from upstream must re-apply these.
158161
| perl | 14 | tree-sitter-perl/tree-sitter-perl | `ea9667dc65a8` | VERIFIED-BOTH | ✅ |
159162
| php | 15 | tree-sitter/tree-sitter-php | `3f2465c217d0` | VERIFIED-BOTH | ✅ |
160163
| pkl | 15 | apple/tree-sitter-pkl | `f5beed1da8e5` | VERIFIED-BOTH | ✅ |
164+
| plsql | 14 | AndreasMaierDe/tree-sitter-plsql | `28aebef209be` | community-niche | ✅ |
161165
| po | 14 | tree-sitter-grammars/tree-sitter-po | `bd860a0f57f6` | VERIFIED-NVIM | ✅ |
162166
| pony | 14 | tree-sitter-grammars/tree-sitter-pony | `73ff874ae4c9` | VERIFIED-NVIM | ✅ |
163167
| powershell | 15 | airbus-cert/tree-sitter-powershell | `73800ecc8bdd` | VERIFIED-BOTH | ✅ |

0 commit comments

Comments
 (0)