beancount-parser-lima 0.16.2

A zero-copy parser for Beancount
Documentation
use std::io::{self, prelude::*};
use std::path::PathBuf;

// for counting allocations
use stats_alloc::{INSTRUMENTED_SYSTEM, Region, StatsAlloc};
use std::alloc::System;

#[global_allocator]
static GLOBAL: &StatsAlloc<System> = &INSTRUMENTED_SYSTEM;

use beancount_parser_lima::{
    BeancountParser, BeancountSources, Directive, ParseError, ParseSuccess,
};

fn main() -> io::Result<()> {
    let flags = xflags::parse_or_exit! {
        /// Show allocations
        optional --show-allocations

        /// File to parse
        required path: PathBuf
    };

    let stderr = &mut io::stderr();

    let sources = if flags.path.to_str() == Some("STDIN") {
        let mut source_string = String::new();
        io::stdin().read_to_string(&mut source_string).unwrap();
        BeancountSources::from(source_string)
    } else {
        BeancountSources::try_from(flags.path)?
    };

    let parser = BeancountParser::new(&sources);

    parse(&sources, &parser, flags.show_allocations, stderr);

    Ok(())
}

fn parse<W>(
    sources: &BeancountSources,
    parser: &BeancountParser,
    show_allocations: bool,
    error_w: &mut W,
) where
    W: Write,
{
    // allocation counting
    let reg = Region::new(GLOBAL);

    if show_allocations {
        eprintln!("Allocations before parsing: {:#?}", reg.change());
    }

    match parser.parse() {
        Ok(ParseSuccess {
            directives,
            options: _,
            plugins: _,
            warnings,
        }) => {
            let mut directives_as_strings = Vec::new();

            if show_allocations {
                eprintln!(
                    "Allocations before printing directives: {:#?}",
                    reg.change()
                );
            }

            fn show_directive(
                directive: &Directive,
                show_allocations: bool,
                directives_as_strings: &mut Vec<String>,
            ) {
                if show_allocations {
                    let directive_as_string = format!("{}", &directive);
                    directives_as_strings.push(directive_as_string);
                    let last_directive = directives_as_strings.last().unwrap();
                    println!("{}\n", last_directive);
                } else {
                    println!("{}\n", &directive);
                }
            }

            for directive in directives {
                show_directive(&directive, show_allocations, &mut directives_as_strings);
            }

            if show_allocations {
                eprintln!("Allocations after printing directives: {:#?}", reg.change());
            }

            sources.write_errors_or_warnings(error_w, warnings).unwrap();
        }
        Err(ParseError { errors, warnings }) => {
            sources.write_errors_or_warnings(error_w, errors).unwrap();
            sources.write_errors_or_warnings(error_w, warnings).unwrap();
        }
    }
}