Tree-sitter grammar for Paradox grand-strategy configuration and scripting files, including Europa Universalis IV, Crusader Kings, and Hearts of Iron. It ships the grammar, highlight queries, generated parser, and bindings for the ecosystems editors and tools use most often.
- Incremental parsing via Tree-sitter
- Highlight queries for editor integrations (
queries/*.scm) - Bindings for Node.js, Python, Rust, Swift, and C
- Corpus tests that lock grammar behavior (
test/corpus) - Comment support for
#, Lua--line comments, and level-0--[[ ... ]]block comments
The Lua-style comments keep this grammar aligned with Foch's hand-written parser, which uses the same conventions for EU4 common/defines/*.lua files.
| Path | Purpose |
|---|---|
grammar.js |
Tree-sitter grammar specification and source of truth |
src/ |
generated C parser sources that ship to consumers |
queries/ |
highlighting and other Tree-sitter queries |
test/corpus |
Tree-sitter CLI corpus fixtures |
bindings/ |
bindings and packaging for Node, Python, Rust, Swift, and C |
tree-sitter.json |
grammar metadata |
- C/C++ toolchain for native builds
- Node.js for the Node binding and tests
- Python 3.10+ for the Python binding and tests
- Rust, optional, for crate builds
- Bun, optional, for
bunx tree-sitter generate - Tree-sitter CLI, optional, for grammar development and corpus tests
- Install with
npm i -g tree-sitter-cli, or use the devDependency vianpx tree-sitter
- Install with
Install dependencies; this builds the native addon:
npm installParse Paradox code:
const Parser = require('tree-sitter');
const Paradox = require('tree-sitter-paradox');
const parser = new Parser();
parser.setLanguage(Paradox);
const source = 'country_event = { id = 42 }';
const tree = parser.parse(source);
console.log(tree.rootNode.toString());Run the Node tests:
npm testInstall the package in editable mode and run the binding test:
pip install -e .[core]
python -m unittest bindings/python/tests/test_binding.pyUse it from Python:
from tree_sitter import Parser
import tree_sitter_paradox as tsp
parser = Parser()
parser.set_language(tsp.language())
source = b"country_event = { id = 42 }"
tree = parser.parse(source)
print(tree.root_node)Add the crate in your Cargo.toml when consuming it from crates.io, or use a path dependency from this repository:
[dependencies]
tree-sitter = "0.25"
tree-sitter-paradox = "0.2"Example usage:
use tree_sitter::{Language, Parser};
use tree_sitter_paradox as paradox;
fn main() {
let mut parser = Parser::new();
parser.set_language(&Language::from(paradox::language())).unwrap();
let source = "country_event = { id = 42 }";
let tree = parser.parse(source, None).unwrap();
println!("{}", tree.root_node().to_sexp());
}Build the crate in this repository:
cargo buildCommon tasks:
-
Run corpus tests with the Tree-sitter CLI:
npx tree-sitter test # or make test
-
Rebuild the native addon for Node:
npm install
-
Build WASM for the playground, optional:
npm run prestart
-
Build the C library, optional:
make
-
Regenerate
src/parser.cafter grammar changes:bunx tree-sitter generate
Run parser regeneration on Linux, macOS, or WSL. Windows node-gyp tooling remains unstable, so the Makefile's "Windows is not supported" line is accurate for grammar developers. Rust consumers of the published crate are unaffected because the regenerated src/parser.c ships with the crate.
When changing grammar.js:
- Keep changes minimal and add or adjust fixtures in
test/corpusto cover new syntax or bug fixes. - Update
queries/*.scmwhen node types or structure changes affect highlighting.
This repository uses the official tree-sitter/workflows reusable workflows for release assets and npm publication. Crates and PyPI are published separately with trusted publishing, so no long-lived registry tokens need to live in GitHub secrets.
Release flow:
- Update the version consistently in
tree-sitter.json,package.json,Cargo.toml, andpyproject.toml. - Merge that change to
master. - The
Version tagworkflow verifies that the four versions match, creates the annotated tagvX.Y.Z, and pushes it. - The tag triggers:
Create releaseviatree-sitter/workflows- npm publication via
tree-sitter/workflows - PyPI wheel and sdist builds in
.github/workflows/package.yml - PyPI publication via trusted publishing in
.github/workflows/package.yml - crates.io publication via trusted publishing in
.github/workflows/package.yml
If you need a manual recovery path, rerun Version tag after fixing the version files, or rerun the existing tag-triggered publish job in GitHub Actions. Publishing itself is intentionally restricted to v* tag pushes.
Repository configuration required:
- GitHub secret
NPM_TOKENfor npm publication - A crates.io trusted publisher configured for this repository with workflow file
package.ymland environmentrelease - A PyPI trusted publisher configured for this repository with workflow file
package.ymland environmentpypi
The first crates.io release still has to be published manually before trusted publishing can be enabled on crates.io.
Any editor integrating Tree-sitter can load this grammar. For Neovim or Helix, use a plugin that sources the parser and queries/highlights.scm, or configure the editor to find the generated library.
AGPL-3.0-only. See LICENSE for details.
- Built on Tree-sitter.
- Inspired by community grammars and Paradox modding documentation.