commit 101287c697c47f91b3da461dfd6658d3337997bc
parent 26af2fa85fcd7e3ae6e0f44eee51581d83e50e3d
Author: Byron Torres <b@torresjrjr.com>
Date: Tue, 1 Feb 2022 22:04:14 +0000
new datetime/parse.ha
Signed-off-by: Byron Torres <b@torresjrjr.com>
Diffstat:
4 files changed, 154 insertions(+), 149 deletions(-)
diff --git a/datetime/format.ha b/datetime/format.ha
@@ -55,155 +55,6 @@ def MONTHS_SHORT: [_]str = [
//
// See https://en.wikipedia.org/wiki/ISO_8601#Time_intervals
-// Parses a datetime string into a [[mock]], using a "layout" format string
-// with a subset of specifiers from POSIX strptime(3). Partial, incremental
-// parsing is possible.
-//
-// datetime::parse(&mok, "%Y-%m-%d", "2038-01-19");
-// datetime::parse(&mok, "%H:%M:%S", "03:14:07");
-//
-export fn parse(mok: *mock, layout: str, s: str) (void | errors::invalid) = {
- const format_iter = strings::iter(layout);
- const s_iter = strings::iter(s);
- let escaped = false;
- for (true) {
- let format_r: rune = match (strings::next(&format_iter)) {
- case void =>
- break;
- case let r: rune =>
- yield r;
- };
-
- if (!escaped && format_r == '%') {
- escaped = true;
- continue;
- };
-
- if (!escaped) {
- let s_r = match (strings::next(&s_iter)) {
- case void =>
- return errors::invalid;
- case let r: rune =>
- yield r;
- };
- if (s_r != format_r) {
- return errors::invalid;
- };
- continue;
- };
-
- escaped = false;
- switch (format_r) {
- // Basic specifiers
- case 'a' =>
- mok.weekday = get_default_locale_string_index(
- &s_iter, WEEKDAYS_SHORT[..])?;
- case 'A' =>
- mok.weekday = get_default_locale_string_index(
- &s_iter, WEEKDAYS[..])?;
- case 'b' =>
- mok.month = get_default_locale_string_index(
- &s_iter, MONTHS_SHORT[..])?;
- case 'B' =>
- mok.month = get_default_locale_string_index(
- &s_iter, MONTHS[..])?;
- case 'd' =>
- let max_n_digits = 2u;
- mok.day = clamp_int(
- get_max_n_digits(&s_iter, max_n_digits)?, 1, 31);
- case 'H' =>
- let max_n_digits = 2u;
- mok.hour = clamp_int(
- get_max_n_digits(&s_iter, max_n_digits)?, 0, 23);
- case 'I' =>
- let max_n_digits = 2u;
- const hour = get_max_n_digits(&s_iter, max_n_digits);
- mok.hour = match (hour) {
- case let hour: int =>
- yield if (hour > 12) {
- yield clamp_int(hour - 12, 1, 12);
- } else {
- yield clamp_int(hour, 1, 12);
- };
- case =>
- return errors::invalid;
- };
- case 'j' =>
- mok.yearday = clamp_int(
- get_max_n_digits(&s_iter, 3)?, 1, 366);
- case 'm' =>
- mok.month = clamp_int(
- get_max_n_digits(&s_iter, 2)?, 1, 12);
- case 'M' =>
- mok.min = clamp_int(
- get_max_n_digits(&s_iter, 2)?, 0, 59);
- case 'N' =>
- mok.nsec = clamp_int(
- get_max_n_digits(&s_iter, 3)?, 0, 999);
- case 'p' =>
- if (mok.hour is void) {
- // We can't change the hour's am/pm because we
- // have no hour.
- return errors::invalid;
- };
- const rest = strings::iter_str(&s_iter);
- if (strings::hasprefix(rest, "AM")) {
- if (mok.hour as int > 12) {
- // 13 AM?
- return errors::invalid;
- } else if (mok.hour as int == 12) {
- mok.hour = 0;
- };
- } else if (strings::hasprefix(rest, "PM")) {
- if (mok.hour as int > 12) {
- // 13 PM?
- return errors::invalid;
- } else if (mok.hour as int < 12) {
- mok.hour =
- (mok.hour as int) + 12;
- };
- } else {
- return errors::invalid;
- };
- strings::next(&s_iter);
- strings::next(&s_iter);
- case 'S' =>
- mok.sec = clamp_int(
- get_max_n_digits(&s_iter, 2)?, 0, 61);
- case 'u', 'w' =>
- mok.weekday = match (get_max_n_digits(&s_iter, 1)) {
- case let i: int =>
- yield if (format_r == 'w') {
- yield if (i == 0) {
- yield 7;
- } else {
- yield clamp_int(i, 1, 7);
- };
- } else {
- yield clamp_int(i, 1, 7);
- };
- case =>
- return errors::invalid;
- };
- case 'U', 'W' =>
- mok.week = clamp_int(
- get_max_n_digits(&s_iter, 2)?, 0, 53);
- case 'Y' =>
- mok.year = get_max_n_digits(&s_iter, 4)?;
- case 'z' =>
- // TODO
- continue;
- case '%' =>
- eat_one_rune(&s_iter, '%')?;
-
- case =>
- // Ignore invalid specifier
- continue;
- };
- };
- return void;
-};
-
// Formats a [[datetime]] and writes it into a caller supplied buffer.
// The returned string is borrowed from this buffer.
export fn bformat(buf: []u8, layout: str, dt: *datetime) (str | errors::invalid | io::error) = {
diff --git a/datetime/parse.ha b/datetime/parse.ha
@@ -0,0 +1,151 @@
+use errors;
+use strings;
+
+// Parses a datetime string into a [[mock]], using a "layout" format string
+// with a subset of specifiers from POSIX strptime(3). Partial, incremental
+// parsing is possible.
+//
+// datetime::parse(&mok, "%Y-%m-%d", "2038-01-19");
+// datetime::parse(&mok, "%H:%M:%S", "03:14:07");
+//
+export fn parse(mok: *mock, layout: str, s: str) (void | errors::invalid) = {
+ const format_iter = strings::iter(layout);
+ const s_iter = strings::iter(s);
+ let escaped = false;
+ for (true) {
+ let format_r: rune = match (strings::next(&format_iter)) {
+ case void =>
+ break;
+ case let r: rune =>
+ yield r;
+ };
+
+ if (!escaped && format_r == '%') {
+ escaped = true;
+ continue;
+ };
+
+ if (!escaped) {
+ let s_r = match (strings::next(&s_iter)) {
+ case void =>
+ return errors::invalid;
+ case let r: rune =>
+ yield r;
+ };
+ if (s_r != format_r) {
+ return errors::invalid;
+ };
+ continue;
+ };
+
+ escaped = false;
+ switch (format_r) {
+ // Basic specifiers
+ case 'a' =>
+ mok.weekday = get_default_locale_string_index(
+ &s_iter, WEEKDAYS_SHORT[..])?;
+ case 'A' =>
+ mok.weekday = get_default_locale_string_index(
+ &s_iter, WEEKDAYS[..])?;
+ case 'b' =>
+ mok.month = get_default_locale_string_index(
+ &s_iter, MONTHS_SHORT[..])?;
+ case 'B' =>
+ mok.month = get_default_locale_string_index(
+ &s_iter, MONTHS[..])?;
+ case 'd' =>
+ let max_n_digits = 2u;
+ mok.day = clamp_int(
+ get_max_n_digits(&s_iter, max_n_digits)?, 1, 31);
+ case 'H' =>
+ let max_n_digits = 2u;
+ mok.hour = clamp_int(
+ get_max_n_digits(&s_iter, max_n_digits)?, 0, 23);
+ case 'I' =>
+ let max_n_digits = 2u;
+ const hour = get_max_n_digits(&s_iter, max_n_digits);
+ mok.hour = match (hour) {
+ case let hour: int =>
+ yield if (hour > 12) {
+ yield clamp_int(hour - 12, 1, 12);
+ } else {
+ yield clamp_int(hour, 1, 12);
+ };
+ case =>
+ return errors::invalid;
+ };
+ case 'j' =>
+ mok.yearday = clamp_int(
+ get_max_n_digits(&s_iter, 3)?, 1, 366);
+ case 'm' =>
+ mok.month = clamp_int(
+ get_max_n_digits(&s_iter, 2)?, 1, 12);
+ case 'M' =>
+ mok.min = clamp_int(
+ get_max_n_digits(&s_iter, 2)?, 0, 59);
+ case 'N' =>
+ mok.nsec = clamp_int(
+ get_max_n_digits(&s_iter, 3)?, 0, 999);
+ case 'p' =>
+ if (mok.hour is void) {
+ // We can't change the hour's am/pm because we
+ // have no hour.
+ return errors::invalid;
+ };
+ const rest = strings::iter_str(&s_iter);
+ if (strings::hasprefix(rest, "AM")) {
+ if (mok.hour as int > 12) {
+ // 13 AM?
+ return errors::invalid;
+ } else if (mok.hour as int == 12) {
+ mok.hour = 0;
+ };
+ } else if (strings::hasprefix(rest, "PM")) {
+ if (mok.hour as int > 12) {
+ // 13 PM?
+ return errors::invalid;
+ } else if (mok.hour as int < 12) {
+ mok.hour =
+ (mok.hour as int) + 12;
+ };
+ } else {
+ return errors::invalid;
+ };
+ strings::next(&s_iter);
+ strings::next(&s_iter);
+ case 'S' =>
+ mok.sec = clamp_int(
+ get_max_n_digits(&s_iter, 2)?, 0, 61);
+ case 'u', 'w' =>
+ mok.weekday = match (get_max_n_digits(&s_iter, 1)) {
+ case let i: int =>
+ yield if (format_r == 'w') {
+ yield if (i == 0) {
+ yield 7;
+ } else {
+ yield clamp_int(i, 1, 7);
+ };
+ } else {
+ yield clamp_int(i, 1, 7);
+ };
+ case =>
+ return errors::invalid;
+ };
+ case 'U', 'W' =>
+ mok.week = clamp_int(
+ get_max_n_digits(&s_iter, 2)?, 0, 53);
+ case 'Y' =>
+ mok.year = get_max_n_digits(&s_iter, 4)?;
+ case 'z' =>
+ // TODO
+ continue;
+ case '%' =>
+ eat_one_rune(&s_iter, '%')?;
+
+ case =>
+ // Ignore invalid specifier
+ continue;
+ };
+ };
+ return void;
+};
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -188,6 +188,7 @@ datetime() {
date.ha \
datetime.ha \
format.ha \
+ parse.ha \
time.ha \
timezone.ha
gen_ssa datetime errors fmt strings strio time time::chrono
diff --git a/stdlib.mk b/stdlib.mk
@@ -940,6 +940,7 @@ stdlib_datetime_any_srcs= \
$(STDLIB)/datetime/date.ha \
$(STDLIB)/datetime/datetime.ha \
$(STDLIB)/datetime/format.ha \
+ $(STDLIB)/datetime/parse.ha \
$(STDLIB)/datetime/time.ha \
$(STDLIB)/datetime/timezone.ha
@@ -2921,6 +2922,7 @@ testlib_datetime_any_srcs= \
$(STDLIB)/datetime/date.ha \
$(STDLIB)/datetime/datetime.ha \
$(STDLIB)/datetime/format.ha \
+ $(STDLIB)/datetime/parse.ha \
$(STDLIB)/datetime/time.ha \
$(STDLIB)/datetime/timezone.ha