shithub: mc

Download patch

ref: a68cb156d015fcebef274f372d2061496acc90c5
parent: 33f429bcdd5beeed24a8650320e9d3a83ce2d6f5
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Aug 29 17:59:25 EDT 2014

Add preliminary, untested parsing.

--- a/lib/date/Makefile
+++ b/lib/date/Makefile
@@ -2,6 +2,8 @@
 MYRSRC= \
 	date.myr \
 	fmt.myr \
+	names.myr \
+	parse.myr \
 	types.myr \
 	zoneinfo.myr \
 
--- a/lib/date/date.myr
+++ b/lib/date/date.myr
@@ -124,6 +124,8 @@
 	-> mkdate(d.actual - (dt castto(std.time)), d.tzname)
 }
 
+
+
 const diff = {a, b
 	-> (b.actual - a.actual) castto(diff)
 }
--- a/lib/date/fmt.myr
+++ b/lib/date/fmt.myr
@@ -1,5 +1,7 @@
 use std
+
 use "types.use"
+use "names.use"
 
 pkg date = 
 	const fmt	: (d : instant, time : bool	-> byte[:])
@@ -37,11 +39,6 @@
 	-> buf[:sz]
 }
 
-const abbrevday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
-const fullday = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
-const abbrevmon = ["NONE", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
-const fullmon = ["NONE", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
-
 const bftime = {buf, f, d
 	var c
 	var o
@@ -52,10 +49,10 @@
 		if c == '%'
 			(c, f) = std.striter(f)
 			match c
-			| 'a':	o += std.bfmt(buf[o:], "%s", abbrevday[d.day])
-			| 'A':	o += std.bfmt(buf[o:], "%s", fullday[d.day])
-			| 'b':	o += std.bfmt(buf[o:], "%s", abbrevmon[d.mon])
-			| 'B':	o += std.bfmt(buf[o:], "%s", fullmon[d.mon])
+			| 'a':	o += std.bfmt(buf[o:], "%s", _names.abbrevday[d.day])
+			| 'A':	o += std.bfmt(buf[o:], "%s", _names.fullday[d.day])
+			| 'b':	o += std.bfmt(buf[o:], "%s", _names.abbrevmon[d.mon])
+			| 'B':	o += std.bfmt(buf[o:], "%s", _names.fullmon[d.mon])
 			| 'c':	o += bftime(buf[o:], "%Y-%m-%d", d)
 			| 'C':	o += std.bfmt(buf[o:], "%02i", d.year % 100)
 			| 'd':	o += std.bfmt(buf[o:], "%02i", d.day)
@@ -66,7 +63,7 @@
 			| 'G':	o += std.bfmt(buf[o:], ...?
 			| 'g':
 			*/
-			| 'h':	o += std.bfmt(buf[o:], "%s", abbrevmon[d.mon])
+			| 'h':	o += std.bfmt(buf[o:], "%s", _names.abbrevmon[d.mon])
 			| 'H':	o += std.bfmt(buf[o:], "%02i", d.h)
 			| 'I':	o += std.bfmt(buf[o:], "%02i", d.h % 12)
 			| 'j':	o += std.bfmt(buf[o:], "year day... unimplemented.")
--- a/lib/date/parse.myr
+++ b/lib/date/parse.myr
@@ -1,11 +1,207 @@
 use std
-use "date.use"
 
+use "types.use"
+use "names.use"
+
 pkg date =
 	/* date i/o */
-	const parse	: (d : byte[:]	-> instant)
-	const parsefmt	: (fmt : byte[:], d : byte[:]	-> instant)
-	const parsez	: (d : byte[:], tz : byte[:]	-> instant)
+	const parse	: (s : byte[:]	-> std.option(instant))
+	const parsez	: (s : byte[:], tz : byte[:]	-> std.option(instant))
+	const parsefmt	: (f : byte[:], s: byte[:]	-> std.option(instant))
+	const parsefmtz	: (f : byte[:], s: byte[:], tz : byte[:]	-> std.option(instant))
 ;;
 
+const Default = "%Y-%m-%d"
 
+const parse	= {s;		-> parsefmtz(Default, s, "")}
+const parsez	= {s, tz;	-> parsefmtz(Default, s, tz)}
+const parsefmt	= {f, s;	-> parsefmtz(f, s, "")}
+const parsefmtz = {f, s, tz
+	var d
+	var err
+
+	err = false
+	s = filldate(&d, f, s, tz, &err)
+	if err || s.len > 0
+		-> `std.None
+	;;
+	-> `std.Some d
+}
+
+generic intval = {s : byte[:], min : @a::(numeric,integral), max : @a::(numeric,integral), err : bool#-> (@a::(numeric,integral), byte[:])
+	var i
+	var c
+	var num
+
+	num = s
+	for i = 0; i < min; i++
+		(c, s) = std.striter(s)
+		if !std.isdigit(c)
+			err# = true
+			-> (0, s)
+		;;
+	;;
+	for i = min ; i < max; i++
+		(c, s) = std.striter(s)
+		if !std.isdigit(c)
+			break
+		;;
+	;;
+	num = num[:i]
+	match std.intparse(num)
+	| `std.Some v:	-> (v, s)
+	| `std.None:
+		err# = true
+		-> (0, s)
+	;;
+}
+
+
+const filldate = {d, f, s, tz, err -> byte[:]
+	var fc, sc
+	var d
+
+	while f.len != 0
+		(fc, f) = std.striter(f)
+		if fc == '%'
+			(fc, f) = std.striter(f)
+			match fc
+			/* named things */
+			| 'a':	(d.day, s) = indexof(s, _names.abbrevday, err)
+			| 'A':	(d.day, s) = indexof(s, _names.fullday, err)
+			| 'b':	(d.day, s) = indexof(s, _names.abbrevmon, err)
+			| 'B':	(d.day, s) = indexof(s, _names.fullmon, err)
+			| 'c':	s = filldate(d, "%Y-%m-%d", s, tz, err)
+			| 'C':	
+				(d.year, s) = intval(s, 2, 2, err)
+				d.year += 1900
+			| 'd':	(d.day, s) = intval(s, 2, 2, err)
+			| 'D':	s = filldate(d, "%m/%d/%y", s, tz, err)
+			| 'e':	(d.day, s) = intval(s, 1, 2, err)
+			| 'F':	s = filldate(d, "%y-%m-%d", s, tz, err)
+			/*
+			| 'G':	o += std.bfmt(buf[o:], ...?
+			| 'g':
+			*/
+			| 'h':	(d.day, s) = indexof(s, _names.abbrevmon, err)
+			| 'H':	(d.h, s) = intval(s, 2, 2, err)
+			| 'I':	(d.h, s) = intval(s, 2, 2, err)
+			| 'j':	std.fatal(1, "year day... unimplemented.")
+			| 'k':	(d.h, s) = intval(s, 1, 2, err)
+			| 'l':	(d.h, s) = intval(s, 1, 2, err)
+			| 'm':	(d.mon, s) = intval(s, 1, 2, err)
+			| 'M':	(d.m, s) = intval(s, 1, 2, err)
+			| 'n':	s = matchstr(s, "\n", err)
+			| 'O':	std.fatal(1, "unsupported %O")
+			| 'p':	s = matchampm(d, s, err)
+			| 'P':	s = matchampm(d, s, err)
+			| 'r':	s = filldate(d, "%H:%M:%S %P", s, tz, err) 
+			| 'R':	s = filldate(d, "%H:%M %P", s, tz, err)
+			| 's':	(d.actual, s) = intval(s, 1, 64, err)
+			| 'S':	(d.s, s) = intval(s, 1, 2, err)
+			| 't':	s = eatspace(s)
+			| 'u':	(d.wday, s) = intval(s, 1, 1, err)
+			| 'U':	std.fatal(1, "week number... unimplemented.")
+				/*
+			| 'x':	o += bftime(buf[o:], Datefmt, d)
+			| 'X':	o += bftime(buf[o:], Timefmt, d)
+				*/
+			| 'y':	(d.year, s) = intval(s, 1, 2, err)
+				d.year += 1900
+			| 'Y':	(d.year, s) = intval(s, 1, 4, err)
+				/*
+			| 'z':	o += timezone(buf[o:], d.tzoff)
+			| 'Z':	o += std.bfmt(buf[o:], "%s", d.tzname)
+				*/
+			| '%':	s = matchstr(s, "%", err)
+			;;
+		else
+			(sc, s) = std.striter(s)
+			if std.isspace(sc)
+				s = eatspace(s)
+			elif (sc != fc)
+				err# = true
+				-> s
+			;;
+		;;
+		if err#
+			-> s
+		;;
+	;;
+	-> s
+}
+
+const eatspace = {s
+	var c
+
+	while std.isspace(std.decode(s))
+		(c, s) = std.striter(s)
+	;;
+	-> s
+}
+
+const indexof = {s, set, err
+	var i
+	for i = 0; i < set.len; i++
+		if s.len >= set[i].len && std.streq(s, set[i])
+			-> (i, s[set[i].len:])
+		;;
+	;;
+	err# = true
+	-> (0, s)
+}
+
+const matchstr = {s, str, err
+	if s.len <= str.len || !std.sleq(s[:str.len], str)
+		err# = true
+		-> ""
+	;;
+	-> s[str.len:]
+}
+
+const matchampm = {d, s, err
+	if s.len < 2
+		err# = true
+		-> s
+	;;
+	if std.sleq(s[:2], "am") || std.sleq(s[:2], "AM")
+		-> s[2:]
+	elif std.sleq(s[:2], "pm") || std.sleq(s[:2], "PM")
+		d.h += 12
+		-> s[2:]
+	else
+		err# = true
+		-> s
+	;;
+}
+
+/*
+const time = {date
+	var t
+	var c, y, ya, m, u
+
+	t = 0
+
+	if date.mon > 2
+		m = (date.mon - 3) castto(std.time)
+	else
+		m = (date.mon + 9) castto(std.time)
+		y = (date.year - 1) castto(std.time)
+	;;
+	
+	c = y / 100
+	ya = y - 100 * c
+	u = (146097 * c) / 4 + \
+		(1461 * ya) / 4 + \
+		(153 * m + 2) / 5 + \
+		(date.day castto(std.time)) + \
+		UnixJulianDiff
+
+	t += (u * 24*60*60*1_000_000)
+	t += (date.h castto(std.time)) * 60*60*1_000_000
+	t += (date.m castto(std.time)) * 60*1_000_000
+	t += (date.s castto(std.time)) * 1_000_000
+	t += date.us castto(std.time)
+	-> t
+}
+*/