Implement 2nd pass.

This commit is contained in:
Dominik Pantůček 2023-03-25 17:12:11 +01:00
parent e7fcb56a66
commit fb7f6bf67e
2 changed files with 62 additions and 15 deletions

View file

@ -46,6 +46,20 @@ value for the key.
The result of parsing is a list of parsed records containing key,
value and line number for further processing.
Member File Processing - Pass 2
-------------------------------
Processed source is scanned for known keys.
Multiple instances of single key are considered an error.
Unknown keys are considered a warning.
Valid multikeys are converted to single key with list of values and
line numbers as the value for such key.
The result is a valid dictionary of keys and multikeys.
Member File Grammar
-------------------

View file

@ -28,7 +28,7 @@
(module
member-parser
(
parse-member-file
load-member-file
member-parser-tests!
)
@ -37,9 +37,14 @@
(chicken io)
(chicken irregex)
member2-record
testing)
testing
dictionary)
;; Removes any comments and removes any leading and trailing
;; TODO: move to separate schema module
(define member-schema-known-keys '(nick mail phone name born joined destroyed))
(define member-schema-known-multikeys '(card desfire credit studentstart studentstop suspendstart suspendstop))
;; Pass 0: Removes any comments and removes any leading and trailing
;; whitespace.
(define (preprocess-member-line line)
(irregex-replace (irregex "[ \\t]*$" 'u)
@ -48,10 +53,10 @@
"")
""))
;; Expects line with comments and surrounding whitespace removed,
;; returns either #f if nothing was parsed, symbol if only one token
;; was there and pair of symbol and string if both key and the value
;; were present.
;; Pass 1: Expects line with comments and surrounding whitespace
;; removed, returns either #f if nothing was parsed, symbol if only
;; one token was there and pair of symbol and string if both key and
;; the value were present.
(define (parse-member-line line)
(if (= (string-length line) 0)
#f
@ -65,7 +70,7 @@
(cons key val))
(string->symbol line)))))
;; Adds parsed lines to member record.
;; Passes 0 and 1: Adds parsed lines to member record.
(define (parse-member-lines mr source)
(let loop ((lines source)
(mr (member-record-set mr #:source source))
@ -88,15 +93,43 @@
result)
(add1 line-number))))))
;; Loads member file source. Performs passes 0 and 1 on each line
;; returning parsed source. Parsed source is a list of lists
;; containing '(key value line-number) information. Leading and
;; trailing whitespace is trimmed for both keys and values.
(define (parse-member-file mr)
;; Pass 2: Converts parsed key/value/line records into a proper
;; dictionary. Known keys are stored as pairs of value and line
;; number, known multikeys as lists of pairs of value and line
;; number.
(define (process-member-file mr)
(let loop ((parsed (dict-ref mr 'parsed))
(mr mr)
(processed (make-dict)))
(if (null? parsed)
(member-record-set mr #:processed processed)
(let* ((line (car parsed))
(key (car line))
(value (cadr line))
(number (caddr line)))
(if (member key member-schema-known-keys)
(if (dict-has-key? processed key)
(loop (cdr parsed)
(member-record-add-highlight mr number "Duplicate key" 2 'error)
processed)
(loop (cdr parsed)
mr
(dict-set processed key (cons value number))))
(if (member key member-schema-known-multikeys)
(loop (cdr parsed)
mr
(dict-set processed key (cons (cons value number)
(dict-ref processed key '()))))
(loop (cdr parsed)
(member-record-add-highlight mr number "Unknown key" 2 'warning)
processed)))))))
;; Loads member file source. Performs passes 0, 1 and 2.
(define (load-member-file mr)
(let* ((mrif (member-record-input-file mr))
(source (read-lines mrif))
(mrp (parse-member-lines mr source)))
mrp))
(process-member-file mrp)))
;; Performs self-tests of the member-parser module.
(define (member-parser-tests!)
@ -138,4 +171,4 @@
(import member-parser)
(member-parser-tests!)
(print (parse-member-file (make-member-record "joe" "members/joe" '())))
(print (load-member-file (make-member-record "joe" "members/joe" '())))