Expressif.Syntax provides the Tree-sitter parser for the Expressif expression language, together with bindings for supported programming languages.
The parser defines the concrete syntax of Expressif independently from its runtime implementations. It is intended to provide a common syntax foundation for the C#, Python and TypeScript implementations of Expressif, as well as editor tooling and language-server support.
About | Repository structure | Development | Releases
Continuous integration builds:
Expressif.Syntax separates the syntax of the Expressif language from its runtime semantics.
The Tree-sitter grammar parses source text into a syntax tree while preserving syntactic constructs such as shorthands. Language-specific bindings can then translate this tree into the semantic representation expected by an Expressif implementation.
For example:
.foo
is represented syntactically as a field-access construct, while:
field(foo)
is represented as a regular function call. Both can later be bound to the same semantic operation:
field(foo)
This separation allows the same parser to support:
- Expressif for C#
- Expressif for Python
- Expressif for TypeScript
- language servers
- syntax highlighting and other editor tooling
Expressif distinguishes record fields from elements of ordered values:
.name named field of the current record
.0 positional field of the current record
^.name named field of the original immutable input record
^.0 positional field of the original immutable input record
$0 first element of the current tuple or array
$1 second element of the current tuple or array
$^0 last element of the current tuple or array
$^1 second-to-last element of the current tuple or array
Record access always uses . for navigation. A leading ^ changes the root
from the current pipeline value to the original immutable input; it does not
change how fields are selected. Access can be chained for nested records, for
example .customer.address or ^.customer.0. The former bracket forms
[name] and [0] are replaced by ^.name and ^.0 respectively.
Element positions are zero-based. $n counts from the beginning and $^n
counts from the end. The parser represents both tuple and array access with the
same positional_element_access node; downstream binders decide whether the
runtime value supports positional access and how invalid or out-of-range access
is handled.
.
├── grammar.js
├── tree-sitter.json
├── package.json
├── src/
│ ├── parser.c
│ ├── grammar.json
│ └── node-types.json
├── bindings/
│ ├── csharp/
│ ├── python/
│ └── typescript/
├── queries/
│ └── highlights.scm
└── test/
grammar.js is the source definition of the Expressif grammar.
The files under src/ are generated by Tree-sitter and are committed to source control so consumers do not need the Tree-sitter CLI to build the parser.
Language-specific integration is located under bindings/.
Install the dependencies:
npm installGenerate the parser:
npx tree-sitter generateRun the grammar tests:
npx tree-sitter testThe grammar should remain independent from the Expressif function catalogue. Parsing determines the syntactic structure of an expression; resolution of functions, predicates, accumulators and their accepted arguments belongs to the language-specific semantic binding layer.
For every push to main, the release workflow independently validates the parser and all bindings, builds the release packages, and calculates the repository version with GitVersion. When validation succeeds and the calculated semantic version has a patch component of 0, it creates the corresponding vX.Y.0 tag and GitHub release. Other versions complete package validation without creating a tag or release.
Each GitHub release contains every validated package produced by scripts/package.ps1:
- the TypeScript/Node package
- the Python wheel and source distribution
- the C# NuGet package
- the native parser source archive
Only the C# package is currently published to an external registry. NuGet publication uses GitHub OIDC trusted publishing to obtain a short-lived API key, so no long-lived NuGet API key is stored in the repository. Configure the trusted publishing policy on NuGet.org with these values:
- Repository Owner:
Seddryck - Repository:
Expressif.Syntax - Workflow File:
release.yml - Environment: leave blank
The policy's NuGet user must be Seddryck, matching the NuGet/login step in the workflow. Python and TypeScript/Node packages remain available as GitHub release artifacts until PyPI and npm publishing are implemented.
- Expressif — C# implementation and reference project
- Expressif documentation — language documentation