Skip to main content

tree-sitter-irules

CI CodeQL npm crates.io PyPI License: MIT

A tree-sitter parser for F5 iRules — the TCL-derived scripting language used to program traffic management on F5 BIG-IP.

Why use this

iRules has almost no modern editor support, so most tools fall back on crude keyword matching. This parser teaches tree-sitter the actual structure of an iRules script — its event handlers, namespaced commands, and operators — which unlocks the tooling other languages take for granted:

  • Real syntax highlighting that knows an event from a command from a variable, and updates as you type. Backed by the shipped queries/irules/highlights.scm.
  • Structural folding of event handlers and blocks, so you can collapse a rule to see its shape at a glance (queries/irules/folds.scm).
  • A foundation for richer tooling — a precise syntax tree is what code navigation (go-to-definition, find-references), linters that catch mistakes (a misspelled event, a command used in the wrong context), and project-wide refactoring are built on. The parse tree is in place; those higher-level features land as the matching queries (locals.scm, tags.scm) and integrations are added.

Because tree-sitter parses incrementally and tolerates errors, this works on every keystroke and even while a rule is half-written.

How iRules differs from TCL

iRules are syntactically a dialect of TCL with three additions:

  • Event handlers: when CLIENT_ACCEPTED { ... }, with optional priority N and timing on|off modifiers.
  • Namespace-qualified built-in commands: HTTP::host, IP::client_addr, LB::server, SSL::cert, TCP::respond, etc.
  • Extra expression operators on top of TCL's eq/ne/in/ni: starts_with, ends_with, contains, equals, matches, matches_regex, matches_glob.

This grammar is built as an extension of tree-sitter-tcl by Lewis Russell, redistributed under the MIT license. See LICENSE.

Recognised iRules surface

Names below come from F5's authoritative sources: Commands.html, iRulesReference.html, Operators.html, and when.html. The list reflects what queries/irules/highlights.scm will tag as @function.builtin; commands outside the list still parse, they just fall through to the generic @function capture.

Namespaced commands (<NS>::<command>):

Group Namespaces
Transport / IP IP, TCP, UDP, SCTP, LINK, VLAN, ROUTE, DATAGRAM, DHCP, FLOW, FLOWTABLE, IPFIX, LSN, NSH, PCP
TLS SSL, CLIENTSSL, SERVERSSL, TLS, X509, IKE
HTTP HTTP, HTTP2, HTTP3, WS, WEBSOCKET, CACHE, COMPRESS, REWRITE, STREAM, URI, JSON, XML, HTML, SSE
Other application DNS, SIP, SDP, RTSP, FTP, MQTT, FIX, DIAMETER, RADIUS, ICAP, GTP, TDS, NTLM, MR, GENERICMESSAGE, CONNECTOR, DNSMSG, IMAP, POP3, SIPALG, SMTPS, SOCKS
Load balancing / virtual LB, POOL, NODE, MEMBER, VIRTUAL, SNAT, SNATPOOL, PERSIST, PROFILE, PROXY, ONECONNECT, RATELIMIT, SCRUBBER, GTM, TMM, TMSH, BWC, ISESSION, IVS, L7CHECK
Access / security ACL, ACCESS, ACCESS2, AAA, AUTH, WEBSSO, VDI, WAM, TAP, ASM, BOTDEFENSE, ANTIFRAUD, DOSL7, CATEGORY, CLASSIFICATION, CLASSIFY, CLASS, ADM, APM, ECA, POLICY, PSC
Adaptation / data ADAPT, PEM, AVR, STATS, TABLE, SESSION, EVENT, LOG, LOGGING, MEMORY, RESOLV, RESOLVER, REST, XLAT, NAME, HSL, ILX, QOE, MATRIX, NS, ISTATS, MESSAGE, SIDEBAND
Crypto / encoding CRYPTO, AES, DES, RC4, HMAC, MD5, SHA1, SHA256, SHA384, SHA512, B64, HEX, BIGNUM, ASN1

Global (non-namespaced) iRules commands also tagged as @function.builtin: accumulate, active_members, active_nodes, after, b64decode, b64encode, call, clientside, clone, collect, connect, crc32, decode_uri, discard, domain, drop, event, findclass, findstr, forward, getfield, htonl, htons, listen, matchclass, member, members, node, nodes, ntohl, ntohs, peer, persist, pool, recv, reject, release, send, serverside, session, sharedvar, snat, snatpool, substr, table, virtual.

Event names are intentionally open: anything matching /[A-Z][A-Z0-9_]*/ parses as an event_name. F5 documents 200+ events across protocol families and adds new ones each BIG-IP release; encoding a closed set in the parser would force a regen on every release. Validate event spellings in a linter, not the parser.

TCL baseline

iRules is a TCL 8.4 dialect (per F5 K6091). TCL 8.5 features (dict, lassign, ** operator, expanded lsearch switches) and TCL 8.6 features (try/on error/finally, lmap, throw) are available on BIG-IP 12.x and later when explicitly enabled. The grammar follows the tree-sitter-tcl baseline, so 8.5/8.6 syntax parses fine — but keep in mind that older BIG-IP runtimes will reject those constructs.

A subset of TCL commands is disabled at runtime in iRules for safety (exec, file, open, socket, and others; see F5's DisabledTclCommands.html). The parser does not enforce the disabled list — disabled commands parse as ordinary TCL commands. Linting/validation is out of scope here.

Known limitations

  • Bare-word operands in expr contexts must be quoted or braced, as in stock TCL. if {$x eq foo} produces an (ERROR ...) node because TCL's own expr rejects unquoted barewords (invalid bareword "foo"); write if {$x eq "foo"} or if {$x eq {foo}}. $var, numbers, booleans, [cmd], and "strings" are all accepted operands.
  • Plain matches operator (no _glob/_regex suffix) is accepted by the grammar but is not documented on F5's Operators page. It is retained for upstream tree-sitter-tcl compatibility; prefer matches_glob or matches_regex.

Status

Early. The grammar parses iRules as TCL plus iRules-specific event handlers and tags iRules namespace commands and globals in queries/irules/highlights.scm.

Building

git clone https://github.com/dekobon/tree-sitter-irules.git
cd tree-sitter-irules
npm install
npx tree-sitter generate
make test

The committed src/parser.c is generated by the exact tree-sitter-cli version recorded in package-lock.json and CI pins to that same version, so contributors must regenerate parser.c with the locally-installed CLI (npx tree-sitter generate) — never with a globally-installed one — when bumping tree-sitter-cli. See AGENTS.md for the full versioning, commit, and changelog conventions.

Using it

Pick the binding for your toolchain. All bindings expose tree_sitter_irules (or the language-idiomatic equivalent) and resolve to the same src/parser.c + src/scanner.c.

No release has been tagged yet, so all snippets below resolve from the default branch. Once a release vX.Y.Z is cut, swap each snippet to a pinned form: Cargo tag = "vX.Y.Z" (instead of branch = "main"), Go @vX.Y.Z (instead of @latest), npm github:dekobon/tree-sitter-irules#vX.Y.Z, pip git+https://github.com/dekobon/tree-sitter-irules@vX.Y.Z, or the published package version once available on the relevant registry.

# Cargo.toml
[dependencies]
tree-sitter-irules = { git = "https://github.com/dekobon/tree-sitter-irules", branch = "main" }
# Go: resolves to a pseudo-version of the latest commit on main.
go get github.com/dekobon/tree-sitter-irules@latest
// package.json
"dependencies": { "tree-sitter-irules": "github:dekobon/tree-sitter-irules" }
# pyproject.toml
[project]
dependencies = ["tree-sitter-irules @ git+https://github.com/dekobon/tree-sitter-irules"]

Bindings ship the parser only. Editor / runtime integrations also need to load queries/irules/highlights.scm (and optionally folds.scm / indents.scm) for highlighting and structural navigation; consult your editor's tree-sitter integration docs for how to register the queries. The Rust binding additionally re-exports the highlights query as HIGHLIGHTS_QUERY.

Filetype detection

The repo ships ftdetect/irules.lua and ftplugin/irules.lua for Neovim. The ftdetect file maps *.irule and *.irules to filetype irules unconditionally; the ftplugin then calls vim.treesitter.start() for that filetype. Highlighting only renders once the parser binary and queries/irules/highlights.scm are registered with nvim-treesitter (or equivalent) — without that, the start() call is a no-op and the buffer falls back to non-treesitter highlighting.

iRules are also commonly stored with a plain .tcl extension — we deliberately do not claim .tcl globally, since most .tcl files on disk are ordinary TCL. To opt specific .tcl files into the iRules parser, pick one of:

  • Modeline at the top of the file: # vim: set filetype=irules :

  • Per-project autocmd in .nvim.lua (sourced after :cd into the project via Neovim's 'exrc'). Note vim.fn.getcwd() is evaluated when the autocmd is defined, so this snippet belongs in a per-project config, not a global init.lua:

    vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, {
      pattern = vim.fn.getcwd() .. "/irules/*.tcl",
      callback = function() vim.bo.filetype = "irules" end,
    })
    
  • Content-based detection for files that always start with a when block:

    vim.filetype.add({
      pattern = {
        [".*%.tcl$"] = function(_, bufnr)
          local first = vim.api.nvim_buf_get_lines(bufnr, 0, 1, false)[1] or ""
          if first:match("^%s*when%s+[A-Z][A-Z0-9_]*") then return "irules" end
        end,
      },
    })
    

Other editors follow the same pattern: keep .tcl mapped to TCL by default and override per-directory or via a header comment.

Layout

  • grammar.js — grammar definition (TCL base + iRules when event handler).
  • queries/irules/ — highlight, fold, and indent queries with iRules-aware tags.
  • test/corpus/ — corpus tests (TCL tests inherited; iRules-specific tests in test/corpus/irules.txt).
  • bindings/ — language bindings (C, Go, Node, Python, Rust, Swift).

Contributing

  • Issues and feature requests: https://github.com/dekobon/tree-sitter-irules/issues
  • Pull requests welcome. Read AGENTS.md first — it documents the Conventional Commits / SemVer / Keep-a-Changelog conventions, the validation gates (npx tree-sitter generate, make test, npm run lint), and the rule that committed src/parser.c must be generated by the tree-sitter-cli version recorded in package-lock.json.

License

MIT. See LICENSE. This grammar is a fork of tree-sitter-tcl by Lewis Russell; original copyright is retained alongside the tree-sitter-irules project copyright.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tree_sitter_irules-0.2.0.tar.gz (67.3 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

tree_sitter_irules-0.2.0-cp311-abi3-win_amd64.whl (52.9 kB view details)

Uploaded CPython 3.11+Windows x86-64

tree_sitter_irules-0.2.0-cp311-abi3-win32.whl (53.8 kB view details)

Uploaded CPython 3.11+Windows x86

tree_sitter_irules-0.2.0-cp311-abi3-musllinux_1_2_x86_64.whl (61.5 kB view details)

Uploaded CPython 3.11+musllinux: musl 1.2+ x86-64

tree_sitter_irules-0.2.0-cp311-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (61.4 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.28+ x86-64manylinux: glibc 2.5+ x86-64

tree_sitter_irules-0.2.0-cp311-abi3-macosx_11_0_arm64.whl (51.5 kB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

File details

Details for the file tree_sitter_irules-0.2.0.tar.gz.

File metadata

  • Download URL: tree_sitter_irules-0.2.0.tar.gz
  • Upload date:
  • Size: 67.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for tree_sitter_irules-0.2.0.tar.gz
Algorithm Hash digest
SHA256 71cf24c4bb7ab781dc876e0a8bb196cdc1a44871e724884a2d34b165a39ab790
MD5 19182e6f7e2a195f377bc45f54d9949b
BLAKE2b-256 9c55e90fd3c22671d53b6074fd0f632d7be0ca253f2a9c63993f0b75d0dc4a33

See more details on using hashes here.

Provenance

The following attestation bundles were made for tree_sitter_irules-0.2.0.tar.gz:

Publisher: release.yml on dekobon/tree-sitter-irules

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tree_sitter_irules-0.2.0-cp311-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for tree_sitter_irules-0.2.0-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 a57cee31c8758b53060dcef779992187b17514c2d24dfca5e4d1e6fc66d41f33
MD5 ac4d37e06450e762b9ddc5014d6b16a3
BLAKE2b-256 750c629a24a5cec39f4baa3a92f0d51ac621456be0e900ee47095c5cc8688a85

See more details on using hashes here.

Provenance

The following attestation bundles were made for tree_sitter_irules-0.2.0-cp311-abi3-win_amd64.whl:

Publisher: release.yml on dekobon/tree-sitter-irules

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tree_sitter_irules-0.2.0-cp311-abi3-win32.whl.

File metadata

File hashes

Hashes for tree_sitter_irules-0.2.0-cp311-abi3-win32.whl
Algorithm Hash digest
SHA256 674030a8c2e1e2a1be0e75c5a394b74760e38124e91c22c9d866601703eeb1a9
MD5 ad205e474a0896d2bd0c0ca65764024c
BLAKE2b-256 38e3849dcfeeb823723698016744444eef7bf61199b62acaa05a6142e45b11f3

See more details on using hashes here.

Provenance

The following attestation bundles were made for tree_sitter_irules-0.2.0-cp311-abi3-win32.whl:

Publisher: release.yml on dekobon/tree-sitter-irules

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tree_sitter_irules-0.2.0-cp311-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for tree_sitter_irules-0.2.0-cp311-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 3503a9575d0f35fbd98806866ef6017581ba14f330b30e333b90a5b527ecf778
MD5 e4f0d81b7538cbfbc78e8c1f41cd3e28
BLAKE2b-256 f9a892ac1279fe2258b45592b16499748427165018787bedfaa9c8da4ef86ebc

See more details on using hashes here.

Provenance

The following attestation bundles were made for tree_sitter_irules-0.2.0-cp311-abi3-musllinux_1_2_x86_64.whl:

Publisher: release.yml on dekobon/tree-sitter-irules

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tree_sitter_irules-0.2.0-cp311-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.

File metadata

File hashes

Hashes for tree_sitter_irules-0.2.0-cp311-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 da5de45d3f34d76365e13449637b822d922204eec54ce66bb9f0e46c81cd02a6
MD5 25310a70b4dde6ec648d79f848c59c3a
BLAKE2b-256 8d3d9e8494c0b95e8924b2f5cfdb3ce7b8d63df16fc35827f80735a4c4f9d07c

See more details on using hashes here.

Provenance

The following attestation bundles were made for tree_sitter_irules-0.2.0-cp311-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl:

Publisher: release.yml on dekobon/tree-sitter-irules

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tree_sitter_irules-0.2.0-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for tree_sitter_irules-0.2.0-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b9a6e96e1cfa6946781c7c4f3cc3cc38c775703f89ed22bd70f50b50cb312180
MD5 03e8df5404147d7c554375b3e3418f24
BLAKE2b-256 f2c90cd24ad36c741a7ec9087b40cc560cacf41ac756138b9f14c8a13b0c5d00

See more details on using hashes here.

Provenance

The following attestation bundles were made for tree_sitter_irules-0.2.0-cp311-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on dekobon/tree-sitter-irules

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.0 This release

6 files

0.1.1

6 files

0.1.0

6 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page