diff options
Diffstat (limited to 'src/times.h')
-rw-r--r-- | src/times.h | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/src/times.h b/src/times.h index c50b0366..b13f48b1 100644 --- a/src/times.h +++ b/src/times.h @@ -181,6 +181,105 @@ private: #endif // HAVE_BOOST_SERIALIZATION }; +class date_specifier_t +{ + friend class date_parser_t; + +#if 0 + typedef date_t::year_type year_type; +#else + typedef unsigned short year_type; +#endif + typedef date_t::month_type month_type; + typedef date_t::day_type day_type; + typedef date_t::day_of_week_type day_of_week_type; + + optional<year_type> year; + optional<month_type> month; + optional<day_type> day; + optional<day_of_week_type> wday; + +public: + date_specifier_t() {} + date_specifier_t(const date_t& date, const date_traits_t& traits) { + if (traits.has_year) + year = date.year(); + if (traits.has_month) + month = date.month(); + if (traits.has_day) + day = date.day(); + } + + date_t begin(const optional<date_t::year_type>& current_year = none) const; + date_t end(const optional<date_t::year_type>& current_year = none) const; + + bool is_within(const date_t& date, + const optional<date_t::year_type>& current_year = none) const { + return date >= begin(current_year) && date < end(current_year); + } + +#if defined(HAVE_BOOST_SERIALIZATION) +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template<class Archive> + void serialize(Archive& ar, const unsigned int /* version */) { + ar & year; + ar & month; + ar & day; + ar & wday; + } +#endif // HAVE_BOOST_SERIALIZATION +}; + +class date_range_t +{ + friend class date_parser_t; + + optional<date_specifier_t> range_begin; + optional<date_specifier_t> range_end; + +public: + optional<date_t> + begin(const optional<date_t::year_type>& current_year = none) const { + if (range_begin) + return range_begin->begin(current_year); + else + return none; + } + optional<date_t> + end(const optional<date_t::year_type>& current_year = none) const { + if (range_end) + return range_end->end(current_year); + else + return none; + } + + bool is_within(const date_t& date, + const optional<date_t::year_type>& current_year = none) const { + optional<date_t> b = begin(current_year); + optional<date_t> e = end(current_year); + bool after_begin = b ? date >= *b : true; + bool before_end = e ? date < *e : true; + return after_begin && before_end; + } + +#if defined(HAVE_BOOST_SERIALIZATION) +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template<class Archive> + void serialize(Archive& ar, const unsigned int /* version */) { + ar & range_begin; + ar & range_end; + } +#endif // HAVE_BOOST_SERIALIZATION +}; + struct date_duration_t { enum skip_quantum_t { @@ -247,6 +346,45 @@ private: #endif // HAVE_BOOST_SERIALIZATION }; +class date_specifier_or_range_t +{ + typedef variant<int, date_specifier_t, date_range_t> value_type; + + value_type specifier_or_range; + +public: + optional<date_t> + begin(const optional<date_t::year_type>& current_year = none) const { + if (specifier_or_range.type() == typeid(date_specifier_t)) + return boost::get<date_specifier_t>(specifier_or_range).begin(current_year); + else if (specifier_or_range.type() == typeid(date_range_t)) + return boost::get<date_range_t>(specifier_or_range).begin(current_year); + else + return none; + } + optional<date_t> + end(const optional<date_t::year_type>& current_year = none) const { + if (specifier_or_range.type() == typeid(date_specifier_t)) + return boost::get<date_specifier_t>(specifier_or_range).end(current_year); + else if (specifier_or_range.type() == typeid(date_range_t)) + return boost::get<date_range_t>(specifier_or_range).end(current_year); + else + return none; + } + +#if defined(HAVE_BOOST_SERIALIZATION) +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template<class Archive> + void serialize(Archive& ar, const unsigned int /* version */) { + ar & specifier_or_range; + } +#endif // HAVE_BOOST_SERIALIZATION +}; + class date_interval_t : public equality_comparable<date_interval_t> { public: @@ -343,9 +481,198 @@ private: #endif // HAVE_BOOST_SERIALIZATION }; +class date_parser_t +{ + friend void show_period_tokens(std::ostream& out, const string& arg); + + class lexer_t + { + friend class date_parser_t; + + string::const_iterator begin; + string::const_iterator end; + + public: + struct token_t + { + enum kind_t { + UNKNOWN, + + TOK_DATE, + TOK_INT, + TOK_SLASH, + TOK_DASH, + TOK_DOT, + + TOK_A_YEAR, + TOK_A_MONTH, + TOK_A_DAY, + TOK_A_WDAY, + + TOK_SINCE, + TOK_UNTIL, + TOK_IN, + TOK_THIS, + TOK_NEXT, + TOK_LAST, + + TOK_YEAR, + TOK_QUARTER, + TOK_MONTH, + TOK_WEEK, + TOK_DAY, + + TOK_YEARLY, + TOK_QUARTERLY, + TOK_BIMONTHLY, + TOK_MONTHLY, + TOK_BIWEEKLY, + TOK_WEEKLY, + TOK_DAILY, + + TOK_YEARS, + TOK_QUARTERS, + TOK_MONTHS, + TOK_WEEKS, + TOK_DAYS, + + END_REACHED + + } kind; + + typedef variant<string, int, date_specifier_t> content_t; + + optional<content_t> value; + + explicit token_t(kind_t _kind = UNKNOWN, + const optional<content_t>& _value = none) + : kind(_kind), value(_value) { + TRACE_CTOR(date_parser_t::lexer_t::token_t, ""); + } + token_t(const token_t& tok) + : kind(tok.kind), value(tok.value) { + TRACE_CTOR(date_parser_t::lexer_t::token_t, "copy"); + } + ~token_t() throw() { + TRACE_DTOR(date_parser_t::lexer_t::token_t); + } + + token_t& operator=(const token_t& tok) { + if (this != &tok) { + kind = tok.kind; + value = tok.value; + } + return *this; + } + + operator bool() const { + return kind != END_REACHED; + } + + string to_string() const { + switch (kind) { + case UNKNOWN: return "UNKNOWN"; + case TOK_DATE: return "TOK_DATE"; + case TOK_INT: return "TOK_INT"; + case TOK_SLASH: return "TOK_SLASH"; + case TOK_DASH: return "TOK_DASH"; + case TOK_DOT: return "TOK_DOT"; + case TOK_A_YEAR: return "TOK_A_YEAR"; + case TOK_A_MONTH: return "TOK_A_MONTH"; + case TOK_A_DAY: return "TOK_A_DAY"; + case TOK_A_WDAY: return "TOK_A_WDAY"; + case TOK_SINCE: return "TOK_SINCE"; + case TOK_UNTIL: return "TOK_UNTIL"; + case TOK_IN: return "TOK_IN"; + case TOK_THIS: return "TOK_THIS"; + case TOK_NEXT: return "TOK_NEXT"; + case TOK_LAST: return "TOK_LAST"; + case TOK_YEAR: return "TOK_YEAR"; + case TOK_QUARTER: return "TOK_QUARTER"; + case TOK_MONTH: return "TOK_MONTH"; + case TOK_WEEK: return "TOK_WEEK"; + case TOK_DAY: return "TOK_DAY"; + case TOK_YEARLY: return "TOK_YEARLY"; + case TOK_QUARTERLY: return "TOK_QUARTERLY"; + case TOK_BIMONTHLY: return "TOK_BIMONTHLY"; + case TOK_MONTHLY: return "TOK_MONTHLY"; + case TOK_BIWEEKLY: return "TOK_BIWEEKLY"; + case TOK_WEEKLY: return "TOK_WEEKLY"; + case TOK_DAILY: return "TOK_DAILY"; + case TOK_YEARS: return "TOK_YEARS"; + case TOK_QUARTERS: return "TOK_QUARTERS"; + case TOK_MONTHS: return "TOK_MONTHS"; + case TOK_WEEKS: return "TOK_WEEKS"; + case TOK_DAYS: return "TOK_DAYS"; + case END_REACHED: return "END_REACHED"; + } + assert(false); + return empty_string; + } + + void unexpected(); + static void expected(char wanted, char c = '\0'); + }; + + token_t token_cache; + + lexer_t(string::const_iterator _begin, + string::const_iterator _end) + : begin(_begin), end(_end) + { + TRACE_CTOR(date_parser_t::lexer_t, ""); + } + lexer_t(const lexer_t& lexer) + : begin(lexer.begin), end(lexer.end), + token_cache(lexer.token_cache) + { + TRACE_CTOR(date_parser_t::lexer_t, "copy"); + } + ~lexer_t() throw() { + TRACE_DTOR(date_parser_t::lexer_t); + } + + token_t next_token(); + void push_token(token_t tok) { + assert(token_cache.kind == token_t::UNKNOWN); + token_cache = tok; + } + token_t peek_token() { + if (token_cache.kind == token_t::UNKNOWN) + token_cache = next_token(); + return token_cache; + } + }; + + string arg; + lexer_t lexer; + + date_interval_t parse_date_expr(); + +public: + date_parser_t(const string& _arg) + : arg(_arg), lexer(arg.begin(), arg.end()) { + TRACE_CTOR(date_parser_t, ""); + } + date_parser_t(const date_parser_t& parser) + : arg(parser.arg), lexer(parser.lexer) { + TRACE_CTOR(date_parser_t, "copy"); + } + ~date_parser_t() throw() { + TRACE_DTOR(date_parser_t); + } + + date_interval_t parse() { + return date_interval_t(); + } +}; + void times_initialize(); void times_shutdown(); +void show_period_tokens(std::ostream& out, const string& arg); +void analyze_period(std::ostream& out, const string& arg); + std::ostream& operator<<(std::ostream& out, const date_duration_t& duration); } // namespace ledger |