A Tree-sitter parser for the Beancount double-entry accounting language.
- Features
- Installation
- Usage
- Editor Integration
- Supported Syntax
- Examples
- Development
- Performance
- Contributing
- License
- References
- ✅ 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
npm install tree-sitter tree-sitter-beancount
Add to your Cargo.toml
:
[dependencies]
tree-sitter = "~0.24.7"
tree-sitter-beancount = "2.3.3"
pip install tree-sitter tree-sitter-beancount
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());
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());
}
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())
With nvim-treesitter:
require'nvim-treesitter.configs'.setup {
ensure_installed = { "beancount" },
highlight = { enable = true },
incremental_selection = { enable = true },
indent = { enable = true },
}
With tree-sitter-langs:
(use-package tree-sitter-langs
:config
(tree-sitter-require 'beancount))
Install the Beancount extension which uses this parser for syntax highlighting.
This parser supports the complete Beancount syntax including:
- ✅ Transactions -
2023-01-01 * "Description"
- ✅ Account declarations -
open
,close
- ✅ Balance assertions -
balance
- ✅ Price declarations -
price
- ✅ Events -
event
- ✅ Notes -
note
- ✅ Documents -
document
- ✅ Custom directives -
custom
- ✅ 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: value
pairs - ✅ Comments -
;comment
- ✅ Options and plugins -
option
,plugin
- ✅ Include statements -
include
- ✅ Unicode account names -
Assets:银行:储蓄账户
- ✅ International currencies - Support for all currency codes
- ✅ Unicode in strings and comments
- ✅ Org-mode sections -
* Heading
,** Subheading
- ✅ Markdown headers -
# Title
,## Subtitle
- ✅ Mixed content - Beancount within documentation
2023-01-15 * "Coffee Shop" "Morning coffee"
Expenses:Food:Coffee 4.50 USD
Assets:Checking:Bank1 -4.50 USD
2023-01-01 open Assets:银行:工商银行 CNY
2023-01-15 * "工资" #salary
Income:工资收入 -8000.00 CNY
Assets:银行:工商银行 8000.00 CNY
2023-01-20 * "Stock Purchase"
Assets:Investments:AAPL 10 AAPL {150.00 USD} @ 151.00 USD
Assets:Checking:Bank1 -1510.00 USD
* 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 USD
- 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-cli
Generate the parser:
tree-sitter generate
Run the test suite:
tree-sitter test
Run specific tests:
tree-sitter test --file-name chinese_characters.txt
Debug parsing:
tree-sitter parse examples/sample.beancount
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
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
Please report bugs and feature requests on GitHub Issues.
- 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
This project is licensed under the MIT License - see the LICENSE file for details.