Skip to content

Commit 4d6f2dd

Browse files
committed
feat(objectscript): add InterSystems IRIS ObjectScript language support
Add ObjectScript (InterSystems IRIS / Caché) as a supported language, covering the UDL class format (.cls), MAC/INT routines (.mac/.int/.rtn), include/macro files (.inc), and IRIS Studio Export XML. Definition extraction (extract_defs.c): Class, Method, ClassMethod, Property, Parameter, Index, Trigger (with body text), XData, Storage, and Query members as graph nodes; base classes from the Extends clause. Call dispatch resolution (extract_calls.c) — four ObjectScript patterns that are structurally invisible to text search: 1. ##class(Pkg.Class).Method() explicit cross-class call 2. ..Method() relative-dot self-call (the dominant intra-class form; large impact on CALLS completeness) 3. $$$Macro macro expansion via a per-project table built from .inc files 4. type inference from %New/%OpenId + declared return types Ensemble production topology (pass_ensemble_routing.c): EnsembleItem nodes per production component and ROUTES_TO edges resolved from ProductionDefinition XData, plus WorkMgr .Queue("##class(X).method") dispatch — all parsed statically at index time, no live IRIS required. Language detection (language.c): .mac/.int/.rtn map to ObjectScript routine directly; .cls (shared with Apex) and .inc (shared with BitBake) are disambiguated by content, defaulting to the existing language on any doubt so neither Apex nor BitBake detection regresses. The two new per-project tables (macros, return types) are threaded through a new internal cbm_extract_file_ex() so the public cbm_extract_file() signature is unchanged. The tree-sitter grammars for ObjectScript UDL and routine are vendored in internal/cbm/vendored/grammars/objectscript_{udl,routine}/ from https://github.com/intersystems/tree-sitter-objectscript (MIT, ABI 15). Refs DeusData#462 Signed-off-by: Thomas Dyar <tdyar@intersystems.com>
1 parent 8c9ac98 commit 4d6f2dd

27 files changed

Lines changed: 3065 additions & 213 deletions

‎Makefile.cbm‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ EXTRACTION_SRCS = \
132132
$(CBM_DIR)/extract_k8s.c \
133133
$(CBM_DIR)/helpers.c \
134134
$(CBM_DIR)/lang_specs.c \
135+
$(CBM_DIR)/macro_table.c \
136+
$(CBM_DIR)/iris_export_xml.c \
135137
$(CBM_DIR)/service_patterns.c
136138

137139
# LSP resolvers (compiled as one unit via lsp_all.c)

‎THIRD_PARTY.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ License summary:
4848
original upstream authors' licenses — see the manifest for per-grammar
4949
provenance.
5050

51+
### tree-sitter-objectscript (UDL + routine)
52+
53+
- **Project:** [intersystems/tree-sitter-objectscript](https://github.com/intersystems/tree-sitter-objectscript)
54+
- **License:** MIT
55+
- **Copyright:** (c) 2025 InterSystems Corporation
56+
- **Vendored at:** `internal/cbm/vendored/grammars/objectscript_udl/`, `internal/cbm/vendored/grammars/objectscript_routine/`
57+
- **Pinned commit:** `a7ffcdf`
58+
- **Notes:** InterSystems-maintained grammar for the ObjectScript language (InterSystems IRIS / Caché). Vendor-maintained; not in nvim-treesitter or Helix registries. Each `scanner.c`'s upstream `#include "../../common/scanner.h"` is repointed to a per-directory `objectscript_common.h` (verbatim copy of upstream `common/scanner.h`).
59+
5160
## Vendored C/C++ Libraries
5261

5362
| Library | Path | License | Project |

‎internal/cbm/cbm.c‎

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -721,11 +721,6 @@ static bool cbm_source_nesting_exceeds(const char *source, int source_len, int c
721721
return false;
722722
}
723723

724-
static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
725-
CBMLanguage language, const char *project,
726-
const char *rel_path, int64_t timeout_micros,
727-
const char **extra_defines, const char **include_paths);
728-
729724
/* Best-effort parse-coverage collection (#963). Walks only the has_error paths
730725
* of the tree and records the 1-based line ranges of the TOP-MOST ERROR/MISSING
731726
* nodes (does not descend into an error subtree — one range per failed region).
@@ -854,17 +849,17 @@ static const char *cbm_error_ranges_str(CBMArena *a, const cbm_error_regions_t *
854849
CBMFileResult *cbm_extract_file(const char *source, int source_len, CBMLanguage language,
855850
const char *project, const char *rel_path, int64_t timeout_micros,
856851
const char **extra_defines, const char **include_paths) {
857-
CBMFileResult *r = cbm_extract_file_impl(source, source_len, language, project, rel_path,
858-
timeout_micros, extra_defines, include_paths);
859-
cbm_index_mark_done(rel_path);
852+
CBMFileResult *r =
853+
cbm_extract_file_ex(source, source_len, language, project, rel_path, timeout_micros,
854+
extra_defines, include_paths, NULL, NULL);
860855
return r;
861856
}
862857

863-
static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
864-
CBMLanguage language, const char *project,
865-
const char *rel_path, int64_t timeout_micros,
866-
const char **extra_defines,
867-
const char **include_paths) {
858+
CBMFileResult *cbm_extract_file_ex(const char *source, int source_len, CBMLanguage language,
859+
const char *project, const char *rel_path,
860+
int64_t timeout_micros, const char **extra_defines,
861+
const char **include_paths, const CBMMacroTable *macro_table,
862+
const CBMReturnTypeTable *return_type_table) {
868863
// Allocate result on heap (arena inside for all string data)
869864
enum { SINGLE = 1 };
870865
CBMFileResult *result = (CBMFileResult *)calloc(SINGLE, sizeof(CBMFileResult));
@@ -894,6 +889,7 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
894889
if (!spec) {
895890
result->has_error = true;
896891
result->error_msg = cbm_arena_strdup(a, "unsupported language");
892+
cbm_index_mark_done(rel_path);
897893
return result;
898894
}
899895

@@ -902,6 +898,7 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
902898
if (!ts_lang) {
903899
result->has_error = true;
904900
result->error_msg = cbm_arena_strdup(a, "no tree-sitter grammar");
901+
cbm_index_mark_done(rel_path);
905902
return result;
906903
}
907904

@@ -921,6 +918,7 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
921918
if (!parser) {
922919
result->has_error = true;
923920
result->error_msg = cbm_arena_strdup(a, "parser alloc failed");
921+
cbm_index_mark_done(rel_path);
924922
return result;
925923
}
926924

@@ -953,6 +951,7 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
953951
result->has_error = true;
954952
result->error_msg =
955953
cbm_arena_strdup(a, timeout_micros > 0 ? "parse timeout" : "parse failed");
954+
cbm_index_mark_done(rel_path);
956955
return result;
957956
}
958957

@@ -977,6 +976,8 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
977976
.rel_path = rel_path,
978977
.module_qn = result->module_qn,
979978
.root = root,
979+
.macro_table = macro_table,
980+
.return_type_table = return_type_table,
980981
};
981982

982983
// Run extractors: defs + imports use separate walks (unique recursion patterns),
@@ -1240,6 +1241,7 @@ static CBMFileResult *cbm_extract_file_impl(const char *source, int source_len,
12401241
// Retain tree for cross-file LSP reuse (caller frees via cbm_free_tree)
12411242
result->cached_tree = tree;
12421243
result->cached_lang = language;
1244+
cbm_index_mark_done(rel_path);
12431245
return result;
12441246
}
12451247

‎internal/cbm/cbm.h‎

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,16 @@ typedef enum {
164164
CBM_LANG_APEX,
165165
CBM_LANG_SOQL,
166166
CBM_LANG_SOSL,
167-
CBM_LANG_KUSTOMIZE, // kustomization.yaml — Kubernetes overlay tool
168-
CBM_LANG_K8S, // Generic Kubernetes manifest (apiVersion: detected)
169-
CBM_LANG_PINE, // Pine Script (TradingView indicator / strategy language)
170-
CBM_LANG_QML, // Qt QML (Qt Modeling Language — declarative UI + embedded JS)
171-
CBM_LANG_CFSCRIPT, // CFML script dialect (.cfc components — Lucee/ColdFusion)
172-
CBM_LANG_CFML, // CFML tag dialect (.cfm templates — Lucee/ColdFusion)
173-
CBM_LANG_MOJO, // Mojo
167+
CBM_LANG_KUSTOMIZE, // kustomization.yaml — Kubernetes overlay tool
168+
CBM_LANG_K8S, // Generic Kubernetes manifest (apiVersion: detected)
169+
CBM_LANG_PINE, // Pine Script (TradingView indicator / strategy language)
170+
CBM_LANG_QML, // Qt QML (Qt Modeling Language — declarative UI + embedded JS)
171+
CBM_LANG_CFSCRIPT, // CFML script dialect (.cfc components — Lucee/ColdFusion)
172+
CBM_LANG_CFML, // CFML tag dialect (.cfm templates — Lucee/ColdFusion)
173+
CBM_LANG_MOJO, // Mojo
174+
CBM_LANG_OBJECTSCRIPT_UDL, // InterSystems ObjectScript UDL (.cls class files)
175+
CBM_LANG_OBJECTSCRIPT_ROUTINE, // InterSystems ObjectScript routine (.mac/.int/.rtn/.inc)
176+
CBM_LANG_OBJECTSCRIPT_EXPORT, // InterSystems Studio Export XML (<Export generator="Cache">)
174177
CBM_LANG_COUNT
175178
} CBMLanguage;
176179

@@ -499,6 +502,24 @@ typedef struct {
499502
int count;
500503
} CBMStringConstantMap;
501504

505+
// Forward declaration: ObjectScript macro table (defined in macro_table.h).
506+
typedef struct CBMMacroTable CBMMacroTable;
507+
508+
// Method-return-type table for ObjectScript variable type inference. Populated
509+
// from definition nodes (method QN -> declared return type) so a later
510+
// `Set x = obj.Method()` can resolve x's class.
511+
#define CBM_RETURN_TYPE_TABLE_CAP 2048
512+
513+
typedef struct {
514+
const char *method_qn;
515+
const char *return_type;
516+
} CBMReturnTypeEntry;
517+
518+
typedef struct {
519+
CBMReturnTypeEntry entries[CBM_RETURN_TYPE_TABLE_CAP];
520+
int count;
521+
} CBMReturnTypeTable;
522+
502523
typedef struct {
503524
CBMArena *arena;
504525
CBMFileResult *result;
@@ -509,9 +530,11 @@ typedef struct {
509530
const char *rel_path;
510531
const char *module_qn;
511532
TSNode root;
512-
EFCache ef_cache; // enclosing function cache
513-
const char *enclosing_class_qn; // for nested class QN computation
514-
CBMStringConstantMap string_constants; // module-level NAME = "value" pairs
533+
EFCache ef_cache; // enclosing function cache
534+
const char *enclosing_class_qn; // for nested class QN computation
535+
CBMStringConstantMap string_constants; // module-level NAME = "value" pairs
536+
const CBMMacroTable *macro_table; // ObjectScript $$$macro table (NULL if none)
537+
const CBMReturnTypeTable *return_type_table; // ObjectScript method return types (NULL if none)
515538
} CBMExtractCtx;
516539

517540
// --- Public API ---
@@ -561,6 +584,18 @@ CBMFileResult *cbm_extract_file(const char *source, int source_len, CBMLanguage
561584
const char **include_paths // NULL-terminated, or NULL
562585
);
563586

587+
// Pipeline-internal variant of cbm_extract_file() carrying ObjectScript
588+
// per-project tables (macro table + method-return-type table). The public
589+
// cbm_extract_file() is a thin wrapper that passes NULL, NULL for both.
590+
CBMFileResult *cbm_extract_file_ex(
591+
const char *source, int source_len, CBMLanguage language, const char *project,
592+
const char *rel_path, int64_t timeout_micros,
593+
const char **extra_defines, // NULL-terminated, or NULL
594+
const char **include_paths, // NULL-terminated, or NULL
595+
const CBMMacroTable *macro_table, // ObjectScript macros, or NULL
596+
const CBMReturnTypeTable *return_type_table // OS return types, or NULL
597+
);
598+
564599
// Free all memory associated with a result.
565600
void cbm_free_result(CBMFileResult *result);
566601

0 commit comments

Comments
 (0)