Tree-sitter grammars for InterSystems ObjectScript.
This repository publishes five related grammars:
objectscript: playground/snippet grammar.objectscript_udl: class-file grammar for.cls.objectscript_core: routine/statement grammar.objectscript_expr: expression grammar.objectscript_routine: routine-file grammar for.mac,.inc,.rtn, and.int.
Grammar extension graph:
objectscript_expr -> objectscript_core -> objectscript_udl -> objectscript
objectscript_expr -> objectscript_core -> objectscript_routine
- npm:
tree-sitter-objectscript - PyPI:
tree-sitter-objectscript(shipstree_sitter_objectscript,tree_sitter_objectscript_udl, andtree_sitter_objectscript_routine) - Rust crates:
tree-sitter-objectscript(UDL grammar)tree-sitter-objectscript-routine(routine grammar)tree-sitter-objectscript-playground(playground grammar)
Language bindings are available under bindings/:
- C:
bindings/c - Go:
bindings/go - Node.js:
bindings/node - Python:
bindings/python - Rust:
bindings/rust,bindings/rust-routine, andbindings/rust-playground - Swift:
bindings/swift
Quick binding checks from repo root:
nvm use
npm ci
cargo test --lib --package tree-sitter-objectscript
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install -U pip setuptools wheel pytest tree-sitter
python3 setup.py build_ext --inplace
PYTHONPATH=$PWD/bindings/python python3 -m pytest -q bindings/python/tests/test_binding.py
npm test
go test ./bindings/go/...
swift test
make testThe routine and playground Rust crates are staged from bindings/rust-routine and
bindings/rust-playground via helper scripts. See
CONTRIBUTING.md for the current local build workflow and the
temporary studio-highlights.scm copy step those staged crates need today.
For Node bindings specifically, .nvmrc pins the expected Node version.
Install the tree-sitter CLI, then run commands from a grammar directory (objectscript, udl, core, expr, or objectscript_routine):
tree-sitter generate
tree-sitter test
tree-sitter buildFor playground work:
tree-sitter build --wasm
tree-sitter playgroundIf you change an upstream grammar (expr or core), regenerate downstream grammars as needed (udl, objectscript, objectscript_routine).
scripts/sync_queries.py manages the canonical query trio for each grammar:
highlights.scmindents.scminjections.scm
It composes the layered query trees for core, udl, objectscript, and
objectscript_routine, then mirrors those composed files into the Python
binding query directories. studio-highlights.scm files are intentionally left
out of that sync process and are maintained separately.
objectscript/test/corpus is treated as a synced corpus directory. On commit, the repository pre-commit hook:
- Replaces
objectscript/test/corpuscontents with files from:core/test/corpusudl/test/corpusobjectscript_routine/test/corpus
- Removes
objectscript/test/corpus/invalid.txt - Removes
objectscript/test/corpus/compiled-header.txt
See CONTRIBUTING.md for setup, workflow, query sync, and binding test instructions.
-
Zed On Zed, you can use
tree-sitter-objectscriptby downloading the InterSystems ObjectScript extension -
Neovim We currently have a PR open with
nvim-treesitter, and if that gets merged in, the setup process will be automated. However, this repo is currently archived, so for now do the following to setup the grammars in neovim:Add the following content to that file: IMPORTANT: Make sure to replace the revision section with the commit that you want.
return { -- configure nvim-treesitter { "nvim-treesitter/nvim-treesitter", init = function() vim.filetype.add({ extension = { cls = "objectscript_udl", mac = "objectscript_routine", inc = "objectscript_routine", int = "objectscript_routine", rtn = "objectscript_routine" }, }) vim.api.nvim_create_autocmd("FileType", { pattern = { "objectscript_udl", "objectscript_routine" }, callback = function(args) vim.treesitter.start(args.buf) end, }) vim.api.nvim_create_autocmd('User', { pattern = 'TSUpdate', callback = function() local parsers = require("nvim-treesitter.parsers") parsers.objectscript_udl = { install_info = { url = "https://github.com/intersystems/tree-sitter-objectscript", revision = "58450fe03f6fa51de38ac689fbf0af63f455494a", location = "udl", queries = "udl/queries", } } parsers.objectscript = { install_info = { url = "https://github.com/intersystems/tree-sitter-objectscript", revision = "58450fe03f6fa51de38ac689fbf0af63f455494a", location = "objectscript", queries = "objectscript/queries", } } parsers.objectscript_routine = { install_info = { url = "https://github.com/intersystems/tree-sitter-objectscript", revision = "58450fe03f6fa51de38ac689fbf0af63f455494a", location = "objectscript_routine", queries = "objectscript_routine/queries", } } end}) end, opts = function(_, opts) opts.ensure_installed = opts.ensure_installed or {} for _, lang in ipairs({ "objectscript_udl", "objectscript_routine", "objectscript" }) do if not vim.tbl_contains(opts.ensure_installed, lang) then table.insert(opts.ensure_installed, lang) end end end, }, }
Add the following content to that file:
;; extends ( element (STag (Name) @_start_tag) (content (CDSect (CData) @injection.content)) (ETag (Name) @_end_tag) (#eq? @_start_tag "Implementation") (#eq? @_end_tag "Implementation") (#set! injection.language "objectscript") ) ( element (STag (Name) @_start_tag) (content (CharData) @injection.content) (ETag (Name) @_end_tag) (#eq? @_start_tag "Implementation") (#eq? @_end_tag "Implementation") (#set! injection.language "objectscript") )
;; XML declaration "xml" @keyword [ "version" "encoding" "standalone" ] @property (EncName) @string.special (VersionNum) @number [ "yes" "no" ] @boolean ;; Processing instructions (PI) @embedded (PI (PITarget) @keyword) ;; Element declaration (elementdecl "ELEMENT" @keyword (Name) @tag) (contentspec (_ (Name) @property)) "#PCDATA" @type.builtin [ "EMPTY" "ANY" ] @string.special.symbol [ "*" "?" "+" ] @operator ;; Entity declaration (GEDecl "ENTITY" @keyword (Name) @constant) (GEDecl (EntityValue) @string) (NDataDecl "NDATA" @keyword (Name) @label) ;; Parsed entity declaration (PEDecl "ENTITY" @keyword "%" @operator (Name) @constant) (PEDecl (EntityValue) @string) ;; Notation declaration (NotationDecl "NOTATION" @keyword (Name) @constant) (NotationDecl (ExternalID (SystemLiteral (URI) @string.special))) ;; Attlist declaration (AttlistDecl "ATTLIST" @keyword (Name) @tag) (AttDef (Name) @property) (AttDef (Enumeration (Nmtoken) @string)) (DefaultDecl (AttValue) @string) [ (StringType) (TokenizedType) ] @type.builtin (NotationType "NOTATION" @type.builtin) [ "#REQUIRED" "#IMPLIED" "#FIXED" ] @attribute ;; Entities (EntityRef) @constant ((EntityRef) @constant.builtin (#any-of? @constant.builtin "&" "<" ">" """ "'")) (CharRef) @constant (PEReference) @constant ;; External references [ "PUBLIC" "SYSTEM" ] @keyword (PubidLiteral) @string.special (SystemLiteral (URI) @markup.link) ;; Processing instructions (XmlModelPI "xml-model" @keyword) (StyleSheetPI "xml-stylesheet" @keyword) (PseudoAtt (Name) @property) (PseudoAtt (PseudoAttValue) @string) ;; Doctype declaration (doctypedecl "DOCTYPE" @keyword) (doctypedecl (Name) @type) ;; Tags (STag (Name) @tag) (ETag (Name) @tag) (EmptyElemTag (Name) @tag) ;; Attributes (Attribute (Name) @property) (Attribute (AttValue) @string) ;; Delimiters & punctuation [ "<?" "?>" "<!" "]]>" "<" ">" "</" "/>" ] @punctuation.delimiter [ "(" ")" "[" "]" ] @punctuation.bracket [ "\"" "'" ] @punctuation.delimiter [ "," "|" "=" ] @operator ;; Text (CharData) @markup ( element (STag (Name) @_start_tag) (content (CDSect (CData) @injection.content)) (ETag (Name) @_end_tag) (#eq? @_start_tag "Implementation") (#eq? @_end_tag "Implementation") (#set! priority 90) ) ( element (STag (Name) @_start_tag) (content (CharData) @injection.content) (ETag (Name) @_end_tag) (#eq? @_start_tag "Implementation") (#eq? @_end_tag "Implementation") (#set! priority 90) ) (CDSect (CDStart) @markup.heading (CData) @markup.raw "]]>" @markup.heading) ;; Misc (Comment) @comment (ERROR) @error
rm -rf ~/.local/share/nvim/site/parser \ ~/.local/share/nvim/site/parser-info \ ~/.local/share/nvim/site/queries
:TSInstall objectscript_udl objectscript_routine objectscript