Browse code
Subdividing parser.lisp
fiddlerwoaroof authored on 28/04/2016 03:02:49
Showing 3 changed files
Showing 3 changed files
1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,148 @@ |
1 |
+(eval-when (:compile-toplevel :load-toplevel :execute) |
|
2 |
+ ;; make sure these classes am ready to go! |
|
3 |
+ (defclass day-entry () |
|
4 |
+ ((date :initarg :date) |
|
5 |
+ (records :initarg :records))) |
|
6 |
+ |
|
7 |
+ (defclass time-record () |
|
8 |
+ ((client :initarg :client) |
|
9 |
+ (ranges :initarg :ranges) |
|
10 |
+ (memo :initarg :memo))) |
|
11 |
+ |
|
12 |
+ (defclass time-obj () |
|
13 |
+ ((hour :initarg :hour) |
|
14 |
+ (minute :initarg :minute) |
|
15 |
+ (second :initarg :second))) |
|
16 |
+ |
|
17 |
+ (defclass date-obj () |
|
18 |
+ ((day-of-week :initarg :day-of-week) |
|
19 |
+ (year :initarg :year) |
|
20 |
+ (month :initarg :month) |
|
21 |
+ (day :initarg :day))) |
|
22 |
+ |
|
23 |
+ (defclass time-mod () |
|
24 |
+ ((amount :initarg :amount) |
|
25 |
+ (unit :initarg :unit :type (member '(:hour :minute)))))) |
|
26 |
+ |
|
27 |
+(defgeneric unparse (token &optional stream) |
|
28 |
+ (:method ((token time-mod) &optional stream) |
|
29 |
+ (with-slots (amount unit) token |
|
30 |
+ (format stream "~@d~a" amount unit))) |
|
31 |
+ (:method ((token date-obj) &optional stream) |
|
32 |
+ (with-slots (day-of-week year month day) token |
|
33 |
+ (format stream "~a ~2,'0d-~2,'0d-~2,'0d" day-of-week year month day))) |
|
34 |
+ (:method ((token time-obj) &optional stream) |
|
35 |
+ (with-slots (hour minute second) token |
|
36 |
+ (format stream "~2,'0d:~2,'0d:~2,'0d" hour minute second))) |
|
37 |
+ (:method ((token time-record) &optional stream) |
|
38 |
+ (with-slots (client ranges memo) token |
|
39 |
+ (format stream "~& start@~{~a~^,~}~% ~a: ~a~%" |
|
40 |
+ (loop for (start . rest) in ranges |
|
41 |
+ for end = (car rest) |
|
42 |
+ for mod = (cadr rest) |
|
43 |
+ collect (format nil "~a--~a~a" |
|
44 |
+ (unparse start) |
|
45 |
+ (if end (unparse end) "") |
|
46 |
+ (if mod (unparse mod) ""))) |
|
47 |
+ client memo))) |
|
48 |
+ (:method ((token day-entry) &optional stream) |
|
49 |
+ (with-slots (date records) token |
|
50 |
+ (format stream "~&-- ~a~&~{~a~}~%" |
|
51 |
+ (unparse date) |
|
52 |
+ (mapcar #'unparse records))))) |
|
53 |
+ |
|
54 |
+(make-simple-equality day-entry :test ==) |
|
55 |
+(make-simple-equality time-record :test ==) |
|
56 |
+(make-simple-equality time-obj :test eql) |
|
57 |
+(make-equality date-obj |
|
58 |
+ (day-of-week ==) |
|
59 |
+ (year) (month) (day)) |
|
60 |
+(make-simple-equality time-mod :test eql) |
|
61 |
+ |
|
62 |
+(defun make-day-entry (date records) |
|
63 |
+ (make-instance 'day-entry :date date :records records)) |
|
64 |
+ |
|
65 |
+(defun make-time-record (ranges memo) |
|
66 |
+ (make-instance 'time-record :client (car memo) :ranges ranges :memo (cadr memo))) |
|
67 |
+ |
|
68 |
+(defun make-time-mod (amnt unt) |
|
69 |
+ (setf unt (string-downcase unt)) |
|
70 |
+ (make-instance 'time-mod |
|
71 |
+ :amount amnt |
|
72 |
+ :unit (string-ecase unt |
|
73 |
+ ("min" :minute) |
|
74 |
+ ("mins" :minute) |
|
75 |
+ ("minutes" :minute) |
|
76 |
+ ("minute" :minute) |
|
77 |
+ ("hr" :hour) |
|
78 |
+ ("hrs" :hour) |
|
79 |
+ ("hour" :hour) |
|
80 |
+ ("hours" :hour)))) |
|
81 |
+ |
|
82 |
+(define-condition parsing-error (parse-error) |
|
83 |
+ ((failed-chunk :initarg :failed-chunk :reader failed-chunk))) |
|
84 |
+ |
|
85 |
+(define-condition invalid-whitespace (parsing-error) () |
|
86 |
+ (:report (lambda (condition stream) |
|
87 |
+ (format stream "~s is invalid whitespace" |
|
88 |
+ (map 'list #'char-code (failed-chunk condition)))))) |
|
89 |
+ |
|
90 |
+(define-condition invalid-day-of-week (parsing-error) |
|
91 |
+ ((day-of-week :initarg :day-of-week :reader day-of-week)) |
|
92 |
+ (:report (lambda (condition stream) |
|
93 |
+ (format stream "~s is not a valid day of the week" |
|
94 |
+ (day-of-week condition))))) |
|
95 |
+ |
|
96 |
+(defun make-date-obj (day-of-week year month day) |
|
97 |
+ (let ((day-of-week (subseq day-of-week 0 3))) |
|
98 |
+ (if (member day-of-week |
|
99 |
+ '("Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun") |
|
100 |
+ :test #'string-equal) |
|
101 |
+ (make-instance 'date-obj :day-of-week day-of-week :year year :month month :day day) |
|
102 |
+ (error 'invalid-day-of-week :day-of-week day-of-week)))) |
|
103 |
+ |
|
104 |
+(defun make-time-obj (hour minute &optional second) |
|
105 |
+ (make-instance 'time-obj :hour hour :minute minute :second second)) |
|
106 |
+ |
|
107 |
+(defmethod-and-inverse == ((date-obj date-obj) (list list)) |
|
108 |
+ (with-slots (day-of-week year month day) date-obj |
|
109 |
+ (every #'== (list day-of-week year month day) list))) |
|
110 |
+ |
|
111 |
+(defmethod-and-inverse == ((time-obj time-obj) (list list)) |
|
112 |
+ (with-slots (hour minute second) time-obj |
|
113 |
+ (every #'== (list hour minute second) list))) |
|
114 |
+ |
|
115 |
+(define-printer (date-obj s) |
|
116 |
+ ((with-slots (day-of-week year month day) date-obj |
|
117 |
+ (format s "~a, ~2,'0d/~2,'0d/~2,'0d" |
|
118 |
+ (subseq (string-capitalize day-of-week) 0 3) |
|
119 |
+ year month day))) |
|
120 |
+ ((with-slots (day-of-week year month day) date-obj |
|
121 |
+ (format s "~a, ~2,'0d/~2,'0d/~2,'0d" |
|
122 |
+ (subseq (string-capitalize day-of-week) 0 3) |
|
123 |
+ year month day)))) |
|
124 |
+ |
|
125 |
+(define-printer (time-obj s) |
|
126 |
+ ((with-slots (hour minute second) time-obj |
|
127 |
+ (format s "~2,'0d:~2,'0d:~2,'0d" hour minute second))) |
|
128 |
+ ((with-slots (hour minute second) time-obj |
|
129 |
+ (format s "~2,'0d:~2,'0d:~2,'0d" hour minute second)))) |
|
130 |
+ |
|
131 |
+(define-printer (day-entry s) |
|
132 |
+ ((with-slots (date records) day-entry |
|
133 |
+ (format s "~d records for ~s" (length records) date))) |
|
134 |
+ ((with-slots (date records) day-entry |
|
135 |
+ (format s "~d records for ~s" (length records) date)))) |
|
136 |
+ |
|
137 |
+(define-printer (time-record s) |
|
138 |
+ ((with-slots (client) time-record |
|
139 |
+ (format s "For ~s" client))) |
|
140 |
+ ((with-slots (client) time-record |
|
141 |
+ (format s "For ~s" client)))) |
|
142 |
+ |
|
143 |
+(define-printer (time-mod s) |
|
144 |
+ ((with-slots (amount unit) time-mod |
|
145 |
+ (format s "~s ~s" amount unit))) |
|
146 |
+ ((with-slots (amount unit) time-mod |
|
147 |
+ (format s "~s ~s" amount unit)))) |
|
148 |
+ |
... | ... |
@@ -1,156 +1,5 @@ |
1 | 1 |
(in-package #:tempores.parser) |
2 | 2 |
|
3 |
-(eval-when (:compile-toplevel :load-toplevel :execute) |
|
4 |
- ;; make sure these classes am ready to go! |
|
5 |
- (defclass day-entry () |
|
6 |
- ((date :initarg :date) |
|
7 |
- (records :initarg :records))) |
|
8 |
- |
|
9 |
- (defclass time-record () |
|
10 |
- ((client :initarg :client) |
|
11 |
- (ranges :initarg :ranges) |
|
12 |
- (memo :initarg :memo))) |
|
13 |
- |
|
14 |
- (defclass time-obj () |
|
15 |
- ((hour :initarg :hour) |
|
16 |
- (minute :initarg :minute) |
|
17 |
- (second :initarg :second))) |
|
18 |
- |
|
19 |
- (defclass date-obj () |
|
20 |
- ((day-of-week :initarg :day-of-week) |
|
21 |
- (year :initarg :year) |
|
22 |
- (month :initarg :month) |
|
23 |
- (day :initarg :day))) |
|
24 |
- |
|
25 |
- (defclass time-mod () |
|
26 |
- ((amount :initarg :amount) |
|
27 |
- (unit :initarg :unit :type (member '(:hour :minute)))))) |
|
28 |
- |
|
29 |
-(defgeneric unparse (token &optional stream) |
|
30 |
- (:method ((token time-mod) &optional stream) |
|
31 |
- (with-slots (amount unit) token |
|
32 |
- (format stream "~@d~a" amount unit))) |
|
33 |
- (:method ((token date-obj) &optional stream) |
|
34 |
- (with-slots (day-of-week year month day) token |
|
35 |
- (format stream "~a ~2,'0d-~2,'0d-~2,'0d" day-of-week year month day))) |
|
36 |
- (:method ((token time-obj) &optional stream) |
|
37 |
- (with-slots (hour minute second) token |
|
38 |
- (format stream "~2,'0d:~2,'0d:~2,'0d" hour minute second))) |
|
39 |
- (:method ((token time-record) &optional stream) |
|
40 |
- (with-slots (client ranges memo) token |
|
41 |
- (format stream "~& start@~{~a~^,~}~% ~a: ~a~%" |
|
42 |
- (loop for (start . rest) in ranges |
|
43 |
- for end = (car rest) |
|
44 |
- for mod = (cadr rest) |
|
45 |
- collect (format nil "~a--~a~a" |
|
46 |
- (unparse start) |
|
47 |
- (if end (unparse end) "") |
|
48 |
- (if mod (unparse mod) ""))) |
|
49 |
- client memo))) |
|
50 |
- (:method ((token day-entry) &optional stream) |
|
51 |
- (with-slots (date records) token |
|
52 |
- (format stream "~&-- ~a~&~{~a~}~%" |
|
53 |
- (unparse date) |
|
54 |
- (mapcar #'unparse records))))) |
|
55 |
- |
|
56 |
- |
|
57 |
-(make-simple-equality day-entry :test ==) |
|
58 |
-(make-simple-equality time-record :test ==) |
|
59 |
-(make-simple-equality time-obj :test eql) |
|
60 |
-(make-equality date-obj |
|
61 |
- (day-of-week ==) |
|
62 |
- (year) (month) (day)) |
|
63 |
-(make-simple-equality time-mod :test eql) |
|
64 |
- |
|
65 |
- |
|
66 |
-(defun make-day-entry (date records) |
|
67 |
- (make-instance 'day-entry :date date :records records)) |
|
68 |
- |
|
69 |
-(defun make-time-record (ranges memo) |
|
70 |
- (make-instance 'time-record :client (car memo) :ranges ranges :memo (cadr memo))) |
|
71 |
- |
|
72 |
-(defun make-time-mod (amnt unt) |
|
73 |
- (setf unt (string-upcase unt)) |
|
74 |
- (make-instance 'time-mod |
|
75 |
- :amount amnt |
|
76 |
- :unit (string-ecase unt |
|
77 |
- ("min" :MINUTE) |
|
78 |
- ("mins" :MINUTE) |
|
79 |
- ("minutes" :MINUTE) |
|
80 |
- ("minute" :MINUTE) |
|
81 |
- ("hr" :HOUR) |
|
82 |
- ("hrs" :HOUR) |
|
83 |
- ("hour" :HOUR) |
|
84 |
- ("hours" :HOUR)))) |
|
85 |
- |
|
86 |
-(define-condition parsing-error (parse-error) |
|
87 |
- ((failed-chunk :initarg :failed-chunk :reader failed-chunk))) |
|
88 |
- |
|
89 |
-(define-condition invalid-whitespace (parsing-error) () |
|
90 |
- (:report (lambda (condition stream) |
|
91 |
- (format stream "~s is invalid whitespace" |
|
92 |
- (map 'list #'char-code (failed-chunk condition)))))) |
|
93 |
- |
|
94 |
- |
|
95 |
-(define-condition invalid-day-of-week (parsing-error) |
|
96 |
- ((day-of-week :initarg :day-of-week :reader day-of-week)) |
|
97 |
- (:report (lambda (condition stream) |
|
98 |
- (format stream "~s is not a valid day of the week" |
|
99 |
- (day-of-week condition))))) |
|
100 |
- |
|
101 |
-(defun make-date-obj (day-of-week year month day) |
|
102 |
- (let ((day-of-week (subseq day-of-week 0 3))) |
|
103 |
- (if (member day-of-week |
|
104 |
- '("Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun") |
|
105 |
- :test #'string-equal) |
|
106 |
- (make-instance 'date-obj :day-of-week day-of-week :year year :month month :day day) |
|
107 |
- (error 'invalid-day-of-week :day-of-week day-of-week)))) |
|
108 |
- |
|
109 |
-(defun make-time-obj (hour minute &optional second) |
|
110 |
- (make-instance 'time-obj :hour hour :minute minute :second second)) |
|
111 |
- |
|
112 |
-(defmethod-and-inverse == ((date-obj date-obj) (list list)) |
|
113 |
- (with-slots (day-of-week year month day) date-obj |
|
114 |
- (every #'== (list day-of-week year month day) list))) |
|
115 |
- |
|
116 |
-(defmethod-and-inverse == ((time-obj time-obj) (list list)) |
|
117 |
- (with-slots (hour minute second) time-obj |
|
118 |
- (every #'== (list hour minute second) list))) |
|
119 |
- |
|
120 |
-(define-printer (date-obj s) |
|
121 |
- ((with-slots (day-of-week year month day) date-obj |
|
122 |
- (format s "~a, ~2,'0d/~2,'0d/~2,'0d" |
|
123 |
- (subseq (string-capitalize day-of-week) 0 3) |
|
124 |
- year month day))) |
|
125 |
- ((with-slots (day-of-week year month day) date-obj |
|
126 |
- (format s "~a, ~2,'0d/~2,'0d/~2,'0d" |
|
127 |
- (subseq (string-capitalize day-of-week) 0 3) |
|
128 |
- year month day)))) |
|
129 |
- |
|
130 |
-(define-printer (time-obj s) |
|
131 |
- ((with-slots (hour minute second) time-obj |
|
132 |
- (format s "~2,'0d:~2,'0d:~2,'0d" hour minute second))) |
|
133 |
- ((with-slots (hour minute second) time-obj |
|
134 |
- (format s "~2,'0d:~2,'0d:~2,'0d" hour minute second)))) |
|
135 |
- |
|
136 |
-(define-printer (day-entry s) |
|
137 |
- ((with-slots (date records) day-entry |
|
138 |
- (format s "~d records for ~s" (length records) date))) |
|
139 |
- ((with-slots (date records) day-entry |
|
140 |
- (format s "~d records for ~s" (length records) date)))) |
|
141 |
- |
|
142 |
-(define-printer (time-record s) |
|
143 |
- ((with-slots (client) time-record |
|
144 |
- (format s "For ~s" client))) |
|
145 |
- ((with-slots (client) time-record |
|
146 |
- (format s "For ~s" client)))) |
|
147 |
- |
|
148 |
-(define-printer (time-mod s) |
|
149 |
- ((with-slots (amount unit) time-mod |
|
150 |
- (format s "~s ~s" amount unit))) |
|
151 |
- ((with-slots (amount unit) time-mod |
|
152 |
- (format s "~s ~s" amount unit)))) |
|
153 |
- |
|
154 | 3 |
(defun .digit () |
155 | 4 |
(.is #'digit-char-p)) |
156 | 5 |
|