tree-sitter-beancount
v2.4.1
Published
a tree-sitter parser for the beancount syntax
Readme
tree-sitter-beancount
A Tree-sitter parser for the Beancount double-entry accounting language.
Table of Contents
- Features
- Installation
- Usage
- Editor Integration
- Supported Syntax
- Examples
- Development
- Performance
- Contributing
- License
- References
Features
- ✅ Complete Beancount syntax support - Parse all Beancount directives and constructs
- ✅ Unicode support - Full support for international characters including Chinese characters in account names
- ✅ Org-mode & Markdown integration - Parse Beancount embedded in Org-mode and Markdown documents
- ✅ High performance - Optimized grammar with excellent parse speeds (8000+ bytes/ms average)
- ✅ Multiple language bindings - Node.js, Rust, and Python support
- ✅ Editor integration ready - Works with Neovim, Emacs, VS Code, and other editors
- ✅ Comprehensive testing - 122+ test cases covering all syntax features
Installation
Node.js
npm install tree-sitter tree-sitter-beancountRust
Add to your Cargo.toml:
[dependencies]
tree-sitter = "~0.24.7"
tree-sitter-beancount = "2.3.3"Python
pip install tree-sitter tree-sitter-beancountUsage
Node.js Usage
const Parser = require('tree-sitter');
const Beancount = require('tree-sitter-beancount');
const parser = new Parser();
parser.setLanguage(Beancount);
const sourceCode = `
2023-01-01 * "Opening Balance"
Assets:Checking:Bank1 1000.00 USD
Equity:Opening-Balances
2023-01-02 * "Coffee" #food
Expenses:Food:Coffee 4.50 USD
Assets:Checking:Bank1 -4.50 USD
`;
const tree = parser.parse(sourceCode);
console.log(tree.rootNode.toString());Rust Usage
use tree_sitter::{Parser, Language};
extern "C" { fn tree_sitter_beancount() -> Language; }
fn main() {
let mut parser = Parser::new();
let language = unsafe { tree_sitter_beancount() };
parser.set_language(language).expect("Error loading Beancount grammar");
let source_code = r#"
2023-01-01 open Assets:Checking:Bank1 USD
2023-01-01 * "Salary"
Income:Salary -5000.00 USD
Assets:Checking:Bank1 5000.00 USD
"#;
let tree = parser.parse(source_code, None).unwrap();
println!("{}", tree.root_node().to_sexp());
}Python Usage
import tree_sitter_beancount as tsbeancount
from tree_sitter import Language, Parser
BEANCOUNT_LANGUAGE = Language(tsbeancount.language(), "beancount")
parser = Parser()
parser.set_language(BEANCOUNT_LANGUAGE)
source_code = b'''
2023-01-01 open Assets:Checking:Bank1 USD
2023-01-01 balance Assets:Checking:Bank1 0.00 USD
2023-01-15 * "Paycheck"
Income:Salary -3000.00 USD
Assets:Checking:Bank1 3000.00 USD
'''
tree = parser.parse(source_code)
print(tree.root_node.sexp())Editor Integration
Neovim
With nvim-treesitter:
require'nvim-treesitter.configs'.setup {
ensure_installed = { "beancount" },
highlight = { enable = true },
incremental_selection = { enable = true },
indent = { enable = true },
}Emacs
With tree-sitter-langs:
(use-package tree-sitter-langs
:config
(tree-sitter-require 'beancount))VS Code
Install the Beancount extension which uses this parser for syntax highlighting.
Supported Syntax
This parser supports the complete Beancount syntax including:
Core Directives
- ✅ Transactions -
2023-01-01 * "Description" - ✅ Account declarations -
open,close - ✅ Balance assertions -
balance - ✅ Price declarations -
price - ✅ Events -
event - ✅ Notes -
note - ✅ Documents -
document - ✅ Custom directives -
custom
Advanced Features
- ✅ Postings with costs -
{100.00 USD},{{100.00 USD}} - ✅ Price annotations -
@ 1.25 EUR,@@ 125.00 EUR - ✅ Arithmetic expressions -
100 + 50 * 2 - ✅ Tags and links -
#tag,^link - ✅ Metadata -
key: valuepairs - ✅ Comments -
;comment - ✅ Options and plugins -
option,plugin - ✅ Include statements -
include
International Support
- ✅ Unicode account names -
Assets:银行:储蓄账户 - ✅ International currencies - Support for all currency codes
- ✅ Unicode in strings and comments
Document Formats
- ✅ Org-mode sections -
* Heading,** Subheading - ✅ Markdown headers -
# Title,## Subtitle - ✅ Mixed content - Beancount within documentation
Examples
Basic Transaction
2023-01-15 * "Coffee Shop" "Morning coffee"
Expenses:Food:Coffee 4.50 USD
Assets:Checking:Bank1 -4.50 USDInternational Example with Chinese Characters
2023-01-01 open Assets:银行:工商银行 CNY
2023-01-15 * "工资" #salary
Income:工资收入 -8000.00 CNY
Assets:银行:工商银行 8000.00 CNYComplex Transaction with Costs and Prices
2023-01-20 * "Stock Purchase"
Assets:Investments:AAPL 10 AAPL {150.00 USD} @ 151.00 USD
Assets:Checking:Bank1 -1510.00 USDOrg-mode Integration
* Personal Finance
** Income
2023-01-01 * "Salary"
Income:Salary -5000.00 USD
Assets:Checking 5000.00 USD
** Expenses
2023-01-02 * "Groceries"
Expenses:Food:Groceries 50.00 USD
Assets:Checking -50.00 USDDevelopment
Setup
- Clone the repository:
git clone https://github.com/polarmutex/tree-sitter-beancount.git
cd tree-sitter-beancount- Install dependencies:
npm install- Install Tree-sitter CLI:
npm install -g tree-sitter-cliBuilding
Generate the parser:
tree-sitter generateTesting
Run the test suite:
tree-sitter testRun specific tests:
tree-sitter test --file-name chinese_characters.txtDebug parsing:
tree-sitter parse examples/sample.beancountPerformance
This parser is optimized for high performance:
- Average speed: 8,755 bytes/ms
- Test coverage: 122 test cases, 100% pass rate
- Parse tree efficiency: Optimized grammar rules minimize backtracking
- Memory usage: Efficient for large files (1000+ transactions)
Performance has been significantly improved through:
- Removal of unnecessary UTF-8 encoding rules
- Optimized regex patterns
- Simplified posting rules
- Strategic tokenization
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Add tests for any new functionality
- Ensure all tests pass:
tree-sitter test - Submit a pull request
Reporting Issues
Please report bugs and feature requests on GitHub Issues.
Development Guidelines
- Follow the existing code style
- Add test cases for new syntax support
- Update documentation for new features
- Ensure grammar changes don't break existing functionality
License
This project is licensed under the MIT License - see the LICENSE file for details.
