Accounting track: to use the parser in an application, see Accounting: Getting started and Parsing (Livebook). This page documents the library implementation.
Beancount.Parser is a native regex-lexer and line-grammar parser that turns
.bean text into the same typed directive structs you build with the public
Beancount.* constructors.
Public API
# Parse text
{:ok, directives} = Beancount.parse_text(bean_text)
# Parse a file
{:ok, directives} = Beancount.parse_file("ledger.bean")
# Lists pass through unchanged
{:ok, directives} = Beancount.parse(directives)
# Raise on failure
directives = Beancount.parse!(bean_text)Parse failures return {:error, %Beancount.Parser.Error{}} with line,
column, message, and optional token fields - never a bare
FunctionClauseError.
Grammar coverage
The parser covers the full Beancount surface syntax used in production ledgers:
- dated directives:
open,close,commodity,balance,price,event,note,document,pad,query,custom - undated directives:
include,option,plugin,pushtag,poptag - transactions with flags, payee, narration, tags, links, metadata, and postings
(amount elision, cost specs
{…}, and price annotations@/@@) - comments (
;), metadata (key: value), and multi-line metadata blocks
New directive structs (Query, Plugin, PushTag, PopTag) implement the
Beancount.Directive protocol so they round-trip through Beancount.render/1.
Round-trip contract
For every golden fixture:
expected = File.read!("expected.bean")
{:ok, directives} = Beancount.parse_text(expected)
assert Beancount.render(directives) == expectedProperty tests also assert parse(render(ledger)) recovers equivalent text for
generated ledgers from Beancount.Property.ledger/0.
Relationship to engines
Beancount.Engine.Elixir uses the parser internally for check/1 and canned
reports in query/2. Beancount.Engine.CLI shells out to bean-check /
bean-query and remains the default engine for validation and arbitrary
BQL. Native parity on the canned report set is proven; swap engines via
config :beancount_ex, engine: Beancount.Engine.Elixir when you want to run
without Python tooling.
Parsing is independent of validation semantics: the parser produces structs; engines decide what is valid.