Skip to content

Commit

Permalink
Merge branch 'master' of github.com:frosklis/dinero-rs
Browse files Browse the repository at this point in the history
  • Loading branch information
frosklis committed Mar 12, 2021
2 parents 1b3062f + 8cc6555 commit d9f13a7
Show file tree
Hide file tree
Showing 10 changed files with 60 additions and 74 deletions.
26 changes: 0 additions & 26 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@ use colored::ColoredString;
use std::fmt;
use std::fmt::{Display, Formatter};

#[derive(Debug)]
pub enum ParserError {
CannotReadFile(String),
UnexpectedInput(Option<String>),
IncludeLoop(String),
}

#[derive(Debug)]
pub enum LedgerError {
TransactionIsNotBalanced,
Expand All @@ -28,25 +21,6 @@ impl Display for Error {
}
}

impl From<ParserError> for Error {
fn from(error: ParserError) -> Self {
match error {
ParserError::CannotReadFile(s) => Error {
message: vec![ColoredString::from(s.as_str())],
},
ParserError::IncludeLoop(s) => Error {
message: vec![ColoredString::from(s.as_str())],
},
ParserError::UnexpectedInput(s) => Error {
message: match s {
None => vec![],
Some(s) => vec![ColoredString::from(s.as_str())],
},
},
}
}
}

impl From<LedgerError> for Error {
fn from(error: LedgerError) -> Self {
eprintln!("{:?}", error);
Expand Down
31 changes: 17 additions & 14 deletions src/grammar/grammar.pest
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Test in https:://pest.rs
//

journal = { SOI ~ (directive | blank_line | transaction | automated_transaction | journal_comment )+ ~ ws* ~EOI}
journal = { SOI ~ (directive | blank_line | transaction | automated_transaction | journal_comment )* ~ ws* ~EOI}
blank_line = {ws* ~ NEWLINE }
directives = {directive* ~ EOI}
journal_comment = {(";" | "!" | "#") ~ (!end ~ ANY)* ~ end}
Expand All @@ -18,8 +18,8 @@ directive = { include | price

include = { "include" ~ws+ ~ glob ~ws*~end}
glob = { string | (!end ~ ANY)* }
price = {"P" ~ ws* ~ date ~ (ws ~ time)? ~ ws+ ~ currency ~ ws* ~number ~ ws* ~ currency ~ws* ~ comment? ~ end}
commodity = { "commodity" ~ ws+ ~ currency ~ ws* ~ comment? ~ end ~
price = {"P" ~ ws* ~ date ~ (ws ~ time)? ~ ws+ ~ commodity_in_directive ~ ws* ~number ~ ws* ~ commodity_in_directive ~ws* ~ comment? ~ end}
commodity = { "commodity" ~ ws+ ~ commodity_in_directive ~ ws* ~ comment? ~ end ~
(sep ~
(
comment
Expand All @@ -28,6 +28,7 @@ commodity = { "commodity" ~ ws+ ~ currency ~ ws* ~ comment? ~ end ~
)?
~end)*
}
commodity_in_directive = { string | unquoted }
payee_dir = { "payee" ~ ws+ ~ payee ~ ws* ~ comment? ~end ~
(sep ~
(
Expand Down Expand Up @@ -69,16 +70,16 @@ flag = { default }
default = {"default"}
// A transaction
transaction_head = {
transaction_date ~ // date
("=" ~ effective_date)? ~ // effective_date
ws+ ~ status? ~ // status
transaction_date ~ // date
("=" ~ effective_date)? ~ // effective_date
(ws+ ~ status)? ~ // status
ws* ~ code? // code
~ ws* ~ description // description
~ ws* ~ ("|" ~ ws* ~payee)? // payee
~ws* ~ comment? }
automated_transaction_head = {
"=" ~ ws* ~ description // description
~ws* ~ comment? } // comment
"=" ~ ws* ~ automated_description // description
~ws* ~ comment? } // comment
transaction = {transaction_head
~ NEWLINE
~ (sep ~ comment ~ end)*
Expand All @@ -95,7 +96,8 @@ quote = _{"\"" | "'"}
payee = { string | (!"|" ~ !";" ~!end ~ ANY)* }
tag = { string | (!"|" ~ !";" ~!end ~ ANY)* }
description = { string | (!"|" ~ !";" ~!end ~ ANY)* }
comment = {";" ~ (!end ~ ANY)*}
automated_description = { string | (!";" ~!end ~ ANY)* }
comment = {";" ~ (!end ~ ANY)* ~ ws*}

posting = { sep ~ status? ~
posting_kind ~
Expand All @@ -115,7 +117,8 @@ posting_kind = { virtual_no_balance | virtual_balance | real}
real = { account }
virtual_no_balance = { "(" ~ account ~ ")" }
virtual_balance = { "[" ~ account ~ "]" }
account = { string | ((unquoted ~ (" " ~ unquoted)*)) ~ (":" ~ (unquoted ~ (" " ~ unquoted)*))* }
account = { string |
((unquoted ~ ( (" - "|" = " ~ " & "|" ") ~ unquoted)*)) ~ (":" ~ (unquoted ~ ( (" - "|" = " ~ " & "|" ") ~ unquoted)*))* }
// Dates
date = { year ~ date_sep ~ month ~ date_sep ~ day }
time = { hour ~ ":" ~ minute ~ (":" ~ second) }
Expand Down Expand Up @@ -152,14 +155,14 @@ primary = {
}

term = _{ variable | money | number | regex | string }
money = { (number ~ ws* ~ currency) | (currency ~ ws* ~ number) }
money = { (number ~ ws* ~ currency) | (currency ~ ws* ~ number) | ("0" ~ &(ws | sep | end ))}
currency = { string | unquoted_no_number }
regex = { "/" ~ (!"/" ~ ANY)* ~ "/"}
string = {
("\"" ~ (("\\\"") | (!"\"" ~ ANY))* ~ "\"") |
("'" ~ (("\\'") | (!"'" ~ ANY))* ~ "'")
}
reserved = _{ "\n" | "+" | "*" | "/" | "\\" | "|" | "%" | "<" | ">" | ":" | "?" | "(" | ")" | ";" | "[" | "]" }
reserved = _{ "\n" | "\t" | "+" | "*" | "/" | "\\" | "|" | "%" | "<" | ">" | ":" | "?" | "(" | ")" | ";" | "[" | "]" }
unquoted = { !reserved ~ !"=" ~ !"-" ~ !"&" ~
(!reserved ~ !SEPARATOR ~ ANY)+ }
currency_parts = _{ !reserved ~ !"=" ~ !"-" ~ !"&" ~
Expand Down Expand Up @@ -192,9 +195,9 @@ variable = {
// helpers
number = { "-"? ~ bigint ~ ("." ~ bigint)? }
bigint = _{ ASCII_DIGIT+ }
ws = _{" "}
ws = _{ " " | "\t" }
sep = _{("\t" | " \t" | " ") ~ SEPARATOR* }
end = _{ EOI | NEWLINE }
end = _{ EOI | NEWLINE | blank_line}


add = { "+" | "-" }
Expand Down
2 changes: 1 addition & 1 deletion src/models/price.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,6 @@ mod tests {
Utc::now().naive_local().date(),
&ledger.prices,
);
assert_eq!(multipliers.len(), 6);
assert_eq!(multipliers.len(), 7);
}
}
2 changes: 1 addition & 1 deletion src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl<'a> Tokenizer<'a> {
}
}
}
Err(e) => eprintln!("{:?}", e),
Err(e) => eprintln!("{:?}: {:?}", &self.file, e),
}
// dbg!(&ledger);
ledger
Expand Down
2 changes: 1 addition & 1 deletion src/parser/tokenizers/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl<'a> Tokenizer<'a> {
_ => {}
}
}
_x => {},
_x => {}
}
}
Tag {
Expand Down
34 changes: 21 additions & 13 deletions src/parser/tokenizers/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::super::Rule;
use crate::models::{Comment, PostingType, PriceType, Transaction, TransactionType};
use crate::parser::utils::{parse_date, parse_rational, parse_string};
use crate::parser::Tokenizer;
use num::rational::BigRational;
use num::{rational::BigRational, BigInt};
use pest::iterators::Pair;

impl<'a> Tokenizer<'a> {
Expand Down Expand Up @@ -32,7 +32,7 @@ impl<'a> Tokenizer<'a> {
}
Rule::status => {}
Rule::code => {}
Rule::description => {
Rule::description | Rule::automated_description => {
transaction.description = parse_string(part).trim().to_string();
}
Rule::payee => {
Expand Down Expand Up @@ -69,6 +69,7 @@ impl<'a> Tokenizer<'a> {
Rule::comment => transaction.comments.push(Comment {
comment: parse_string(part),
}),
Rule::blank_line => {}
x => panic!("{:?}", x),
}
}
Expand Down Expand Up @@ -136,29 +137,35 @@ fn parse_posting(raw: Pair<Rule>, default_payee: &Option<String>) -> RawPosting
};
let mut money = part.into_inner().next().unwrap().into_inner();
let amount: BigRational;
let currency: String;
let money_part = money.next().unwrap();
if money_part.as_rule() == Rule::number {
amount = parse_rational(money_part);
currency = parse_string(money.next().unwrap());
} else {
currency = parse_string(money_part);
amount = parse_rational(money.next().unwrap());
let mut currency = None;
match money.next() {
Some(money_part) => match money_part.as_rule() {
Rule::number => {
amount = parse_rational(money_part);
currency = Some(parse_string(money.next().unwrap()));
}
Rule::currency => {
currency = Some(parse_string(money_part));
amount = parse_rational(money.next().unwrap());
}
_ => amount = BigRational::new(BigInt::from(0), BigInt::from(1)),
},
None => amount = BigRational::new(BigInt::from(0), BigInt::from(1)),
}

match rule {
Rule::amount => {
posting.money_amount = Some(amount);
posting.money_currency = Some(currency);
posting.money_currency = currency;
}
Rule::cost => {
posting.cost_amount = Some(amount);
posting.cost_currency = Some(currency);
posting.cost_currency = currency;
posting.cost_type = cost_type;
}
Rule::balance => {
posting.balance_amount = Some(amount);
posting.balance_currency = Some(currency);
posting.balance_currency = currency;
}
x => panic!("Expected amount, cost or balance {:?}", x),
}
Expand All @@ -168,6 +175,7 @@ fn parse_posting(raw: Pair<Rule>, default_payee: &Option<String>) -> RawPosting
Rule::comment => posting.comments.push(Comment {
comment: parse_string(part),
}),
Rule::blank_line => {}
x => panic!("{:?}", x),
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/example_files/automated.ledger
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
= @"My favorite restaurant"
; :yummy:

2021-01-01 * Flights
2021-01-01=2021-01-02
Income:Salary -1000 EUR
Assets:Checking account
2021-01-05 * Rent
Expand Down
25 changes: 14 additions & 11 deletions tests/example_files/demo.ledger
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,45 @@
2021-01-01 * Groceries
; :fruit:
Expenses:Groceries $100
Assets:Bank:Checking account
Assets:Bank - 1:Checking account

2021-01-03 * Clothing
; :skirt:
Expenses:Clothes $69.37
Assets:Bank:Checking account $-69.37
Assets:Bank - 1:Checking account $-69.37

2021-01-15 * Flights
; destination: spain
Expenses:Unknown 200 EUR ; this will get translated to Expenses:Flights
Assets:Bank:Checking account $-210.12
Assets:Bank - 1:Checking account $-210.12

2021-01-16 * Alphabet Inc.
Assets:Shares 2 GOOGL @ $957.37
Assets:Bank:Checking account
Assets:Bank - 1:Checking account

2021-01-16 * ACME.
Assets:Shares 2 ACME @@ $957.37
Assets:Bank:Checking account
Assets:Bank - 1:Checking account

2021-01-27 * ACME, inc.
Income:Salary $-100
Assets:Bank:Checking account
Assets:Bank - 1:Checking account

commodity €
alias EUR
alias EURUSD=X
commodity USD
alias $
P 2021-01-23 AAPL 139.07 USD
; Difficult things to parse that were in my ledger
P 2018/01/14 17:37:11 BTC 13420.7 USD
P 2013/12/11 EURUSD=X 1.376444 USD
P 2015/08/07 ETH-USD 2.772120 USD

payee ACME, inc.
alias (?i)(.*acme.*)
account Expenses:Travel
payee Flights
payee Flights

; Difficult things to parse that were in my ledger
P 2018/01/14 17:37:11 BTC 13420.7 USD
P 2013/12/11 EURUSD=X 1.376444 USD
P 2015/08/07 ETH-USD 2.772120 USD
commodity Acme_2021
P 2015/08/07 Acme_2021 1000 USD
4 changes: 2 additions & 2 deletions tests/test_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ fn prices_command() {
let args = &["prices", "-f", "tests/example_files/demo.ledger"];
let assert_1 = Command::cargo_bin("dinero").unwrap().args(args).assert();
let output = String::from_utf8(assert_1.get_output().to_owned().stdout).unwrap();
assert_eq!(output.lines().into_iter().count(), 7);
assert_eq!(output.lines().into_iter().count(), 8);

test_args(args);
}
Expand All @@ -226,7 +226,7 @@ fn commodities_command() {
let assert_1 = Command::cargo_bin("dinero").unwrap().args(args).assert();
let output = String::from_utf8(assert_1.get_output().to_owned().stdout).unwrap();

assert_eq!(output.lines().into_iter().count(), 7);
assert_eq!(output.lines().into_iter().count(), 8);
test_args(args);
}

Expand Down
6 changes: 2 additions & 4 deletions tests/test_failures.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use dinero::parser::Tokenizer;

use assert_cmd::Command;
use std::path::PathBuf;

#[test]
#[should_panic(expected = "Should be money.")]
/// The expression in an automated account should evaluate to money
Expand All @@ -23,5 +20,6 @@ fn not_money() {
assert!(true);

// But to a wrong ledger -- panics!
let ledger = parsed.to_ledger(false);
let _ledger = parsed.to_ledger(false);
unreachable!("This has panicked")
}

0 comments on commit d9f13a7

Please sign in to comment.