summaryrefslogtreecommitdiff
path: root/src/times.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/times.h')
-rw-r--r--src/times.h327
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