Crate beancount_parser_lima
source ·Expand description
beancount-parser-lima
A zero-copy parser for Beancount in Rust.
It is intended to be a complete implementation of the Beancount file format, except for those parts which are deprecated and other features as documented here (in a list which may not be comprehensive).
Currently under active development. APIs are subject to change, but I hope not majorly.
The slightly strange name is because of a somewhat careless failure on my part to notice the existing beancount-parser when starting this project, for which apologies.
(Note that zero-copy support from Chumsky is currently available only in alpha releases.)
Features
-
beautiful error messages, thanks to Ariadne
-
interface for applications to also report beautiful errors in their original context, as in the example below
-
focus on conceptual clarity of application domain objects mapped to Rust types

Roadmap
-
create Python bindings, so that this could be a drop-in replacement for the existing Beancount parser (which is not to say it will necessarily become that!)
-
improve API in the light of experience, i.e. when it gets some use 😅
-
address mistakes, misunderstandings, and edge-cases in the initial implementation as they are discovered
Uncertainties / TODOs
Yeah, Beancount is complicated, and I may have made some mistakes here. Current list of uncertainties, which is certainly not comprehensive.
- metadata tags/links for a directive get folded in with those in the directive header line
Unsupported
This is an incomplete list of what is currently unsupported.
- plugins
Unsupported Options
allow_pipe_separator
allow_deprecated_none_for_tags_and_links
default_tolerance
experiment_explicit_tolerances
insert_pythonpath
plugin
plugin_processing_mode
tolerance
use_legacy_fixed_tolerances
Also, unary options are not supported.
Alternatives
beancount-parser is another parser for Beancount which predates this one, using nom instead of Chumsky.
License
Licensed under either of
- Apache License, Version 2.0 LICENSE-APACHE
- MIT license LICENSE-MIT
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Examples
This example generates the output as shown above.
use beancount_parser_lima::{
BeancountParser, BeancountSources, DirectiveVariant, ParseError, ParseResult,
};
fn main() {
let stderr = &io::stderr();
let sources = BeancountSources::new(PathBuf::from("examples/data/error-post-balancing.beancount"));
let beancount_parser = BeancountParser::new(&sources);
match beancount_parser.parse() {
Ok(ParseResult {
directives,
options: _,
mut warnings,
}) => {
let mut errors = Vec::new();
for directive in directives {
if let DirectiveVariant::Transaction(transaction) = directive.variant() {
let mut postings = transaction.postings().collect::<Vec<_>>();
let n_postings = postings.len();
let n_amounts = itertools::partition(&mut postings, |p| p.amount().is_some());
if postings.is_empty() {
warnings.push(directive.warning("no postings"));
} else if n_amounts + 1 < n_postings {
errors.push(
directive
.error("multiple postings without amount specified")
.related_to_all(postings[n_amounts..].iter().copied()),
);
} else if n_amounts == n_postings {
let total: Decimal =
postings.iter().map(|p| p.amount().unwrap().value()).sum();
if total != Decimal::ZERO {
let last_amount = postings.pop().unwrap().amount().unwrap();
let other_amounts = postings.iter().map(|p| p.amount().unwrap());
errors.push(
last_amount
.error(format!("sum is {}, expected zero", total))
.related_to_all(other_amounts)
.in_context(&directive),
)
}
}
}
}
sources.write(stderr, errors).unwrap();
sources.write(stderr, warnings).unwrap();
}
Err(ParseError { errors, warnings }) => {
sources.write(stderr, errors).unwrap();
sources.write(stderr, warnings).unwrap();
}
}
}
Re-exports
pub use types::*;
Modules
Structs
- The Beancount parser itself, which tokenizes and parses the source files contained in
BeancountSources
. - Contains the content of the Beancount source file, and the content of the transitive closure of all the include’d source files.
- All options read in from
option
pragmas, excluding those for internal processing only. - The value returned when parsing fails.
- The result of parsing all the files, containing date-ordered
Directive
s,Options
, and anyWarning
s.