summaryrefslogtreecommitdiff
path: root/email
diff options
context:
space:
mode:
Diffstat (limited to 'email')
-rw-r--r--email/base64.scm16
-rw-r--r--email/email.scm398
-rw-r--r--email/quoted-printable.scm68
-rw-r--r--email/utils.scm46
4 files changed, 264 insertions, 264 deletions
diff --git a/email/base64.scm b/email/base64.scm
index 6b11b3f..94b7388 100644
--- a/email/base64.scm
+++ b/email/base64.scm
@@ -142,9 +142,9 @@
(put p #\=)))))))
(extract)))))
- ;; Decodes a base64 string. The string must contain only pure
- ;; unpadded base64 data.
-
+;; Decodes a base64 string. The string must contain only pure
+;; unpadded base64 data.
+
(define base64-decode
(case-lambda
((str)
@@ -199,11 +199,11 @@
(eof-object)
(f (get-line port))))
- ;; Reads the common -----BEGIN/END type----- delimited format from
- ;; the given port. Returns two values: a string with the type and a
- ;; bytevector containing the base64 decoded data. The second value
- ;; is the eof object if there is an eof before the BEGIN delimiter.
-
+;; Reads the common -----BEGIN/END type----- delimited format from
+;; the given port. Returns two values: a string with the type and a
+;; bytevector containing the base64 decoded data. The second value
+;; is the eof object if there is an eof before the BEGIN delimiter.
+
(define (get-delimited-base64 port)
(define (get-first-data-line port)
;; Some MIME data has header fields in the same format as mail
diff --git a/email/email.scm b/email/email.scm
index ccda3ac..d836908 100644
--- a/email/email.scm
+++ b/email/email.scm
@@ -33,26 +33,26 @@
#:use-module (email base64)
#:use-module (email quoted-printable)
#:use-module ((email utils)
- #:select (get-line-with-delimiter
- read-objects read-while
- acons* alist-delete*))
+ #:select (get-line-with-delimiter
+ read-objects read-while
+ acons* alist-delete*))
#:export (<email>
- make-email
- email?
- email-headers
- email-body
- <mime-entity>
- make-mime-entity
- mime-entity?
- mime-entity-headers
- mime-entity-body
- email->headers+body
- parse-email
- parse-email-headers
- parse-email-body
- parse-email-address
- interpret-address
- mbox->emails))
+ make-email
+ email?
+ email-headers
+ email-body
+ <mime-entity>
+ make-mime-entity
+ mime-entity?
+ mime-entity-headers
+ mime-entity-body
+ email->headers+body
+ parse-email
+ parse-email-headers
+ parse-email-body
+ parse-email-address
+ interpret-address
+ mbox->emails))
(define (flatten-and-filter terms tree)
(filter list? (keyword-flatten terms tree)))
@@ -98,7 +98,7 @@
;; Printable ASCII characters and UTF-8 characters > \x7f (RFC6532)
(define-peg-pattern vchar body
(and (not-followed-by (or (range #\Nul #\Space)
- "\x7f"))
+ "\x7f"))
peg-any))
(define-peg-pattern wsp body
@@ -110,7 +110,7 @@
(define-syntax-rule (define-printable-ascii-character-pattern name . exceptions)
(define-peg-pattern name body
(and (not-followed-by (or . exceptions))
- vchar)))
+ vchar)))
;;; Quoted characters
@@ -383,7 +383,7 @@
;; TODO: What is a CTL in RFC2045?
(define-peg-pattern token body
(+ (and (not-followed-by (or " " crlf tspecials))
- peg-any)))
+ peg-any)))
;; TODO: Implement iana-token, ietf-token and x-token
(define-peg-pattern iana-token body
@@ -474,31 +474,31 @@
;; RFC5322.
(define-peg-pattern fields all
(* (or trace
- resent-date
- resent-from
- resent-sender
- resent-to
- resent-cc
- resent-bcc
- resent-msg-id
- orig-date
- from
- sender
- reply-to
- to
- cc
- bcc
- message-id
- in-reply-to
- references
- subject
- comments
- keywords
- mime-version
- content
- disposition
- encoding
- optional-field)))
+ resent-date
+ resent-from
+ resent-sender
+ resent-to
+ resent-cc
+ resent-bcc
+ resent-msg-id
+ orig-date
+ from
+ sender
+ reply-to
+ to
+ cc
+ bcc
+ message-id
+ in-reply-to
+ references
+ subject
+ comments
+ keywords
+ mime-version
+ content
+ disposition
+ encoding
+ optional-field)))
(define-peg-pattern mime-extension-field-name all
(and "Content-" (+ ftext)))
@@ -508,25 +508,25 @@
(define-peg-pattern mime-entity-fields all
(* (or content
- disposition
- encoding
- mime-extension-field
- optional-field)))
+ disposition
+ encoding
+ mime-extension-field
+ optional-field)))
(define (decode-mime-encoded-word word)
(regexp-substitute/global
#f "=\\?([^?]*)\\?([^?]*)\\?([^?]*)\\?=" word
'pre (lambda (match-record)
- (let ((charset (match:substring match-record 1))
- (encoding (string->lcase-symbol (match:substring match-record 2)))
- (encoded-text (match:substring match-record 3)))
- (bytevector->string
- ((case encoding
- ((b) base64-decode)
- ((q) q-encoding-decode)
- (else (error "Encoding of MIME word unknown" word)))
- encoded-text)
- charset)))
+ (let ((charset (match:substring match-record 1))
+ (encoding (string->lcase-symbol (match:substring match-record 2)))
+ (encoded-text (match:substring match-record 3)))
+ (bytevector->string
+ ((case encoding
+ ((b) base64-decode)
+ ((q) q-encoding-decode)
+ (else (error "Encoding of MIME word unknown" word)))
+ encoded-text)
+ charset)))
'post))
(define (body->mime-entities body boundary)
@@ -534,13 +534,13 @@
explained in RFC2045), and return that list."
(define (read-till-boundary port)
(read-while port get-line-with-delimiter
- (negate (cut string-prefix? (string-append "--" boundary) <>))))
+ (negate (cut string-prefix? (string-append "--" boundary) <>))))
(define (read-mime-entity port)
(if (string-prefix? (string-append "--" boundary "--")
- (get-line-with-delimiter port))
- (eof-object)
- (read-till-boundary port)))
+ (get-line-with-delimiter port))
+ (eof-object)
+ (read-till-boundary port)))
(call-with-input-string body
(lambda (port)
@@ -552,12 +552,12 @@ explained in RFC2045), and return that list."
(call-with-input-string email
(lambda (port)
(let ((headers (read-while port get-line-with-delimiter
- (lambda (line)
- (not (or (string= line "\n")
- (string= line "\r\n")))))))
- (get-line-with-delimiter port)
- (values headers
- (read-while port get-line-with-delimiter identity))))))
+ (lambda (line)
+ (not (or (string= line "\n")
+ (string= line "\r\n")))))))
+ (get-line-with-delimiter port)
+ (values headers
+ (read-while port get-line-with-delimiter identity))))))
(define (post-process-content-transfer-encoding _ value)
(list 'content-transfer-encoding (string->lcase-symbol value)))
@@ -565,47 +565,47 @@ explained in RFC2045), and return that list."
(define post-process-content-type
(match-lambda*
(`(content (type ,type)
- (subtype ,subtype)
- . ,parameters)
+ (subtype ,subtype)
+ . ,parameters)
(let ((type (string->lcase-symbol type))
- (subtype (string->lcase-symbol subtype)))
+ (subtype (string->lcase-symbol subtype)))
`(content-type
- ,(acons* 'type type
- 'subtype subtype
- (let ((parameters
- (map (match-lambda
- (`(parameter (attribute ,attribute)
- (value ,value))
- (cons (string->lcase-symbol attribute) value)))
- (flatten-and-filter '(parameter) parameters))))
- (if (and (eq? type 'text)
- (not (assoc-ref parameters 'charset)))
- ;; UTF-8 is specified as the default charset in RFC6657
- (acons 'charset "utf-8" parameters)
- parameters))))))))
+ ,(acons* 'type type
+ 'subtype subtype
+ (let ((parameters
+ (map (match-lambda
+ (`(parameter (attribute ,attribute)
+ (value ,value))
+ (cons (string->lcase-symbol attribute) value)))
+ (flatten-and-filter '(parameter) parameters))))
+ (if (and (eq? type 'text)
+ (not (assoc-ref parameters 'charset)))
+ ;; UTF-8 is specified as the default charset in RFC6657
+ (acons 'charset "utf-8" parameters)
+ parameters))))))))
(define post-process-content-disposition
(match-lambda*
(`(disposition ,type . ,parameters)
`(content-disposition
,(acons 'type (string->lcase-symbol type)
- (map (match-lambda
- (('filename-parm ('value filename))
- (cons 'filename (basename filename)))
- (((? (lambda (date-parm)
- (member date-parm '(creation-date-parm modification-date-parm read-date-parm)))
- date-parm) value)
- ;; TODO: Convert to SRFI-19 datetime
- (cons date-parm value))
- (('size-parm value)
- (cons 'size (string->number value)))
- (`(parameter (attribute ,attribute)
- (value ,value))
- (cons (string->lcase-symbol attribute) value)))
- (flatten-and-filter
- '(filename-parm creation-date-parm modification-date-parm
- read-date-parm size-parm parameter)
- parameters)))))))
+ (map (match-lambda
+ (('filename-parm ('value filename))
+ (cons 'filename (basename filename)))
+ (((? (lambda (date-parm)
+ (member date-parm '(creation-date-parm modification-date-parm read-date-parm)))
+ date-parm) value)
+ ;; TODO: Convert to SRFI-19 datetime
+ (cons date-parm value))
+ (('size-parm value)
+ (cons 'size (string->number value)))
+ (`(parameter (attribute ,attribute)
+ (value ,value))
+ (cons (string->lcase-symbol attribute) value)))
+ (flatten-and-filter
+ '(filename-parm creation-date-parm modification-date-parm
+ read-date-parm size-parm parameter)
+ parameters)))))))
(define post-process-optional-field
(match-lambda*
@@ -613,7 +613,7 @@ explained in RFC2045), and return that list."
(field-name ,field-name)
,field-value)
(list (string->lcase-symbol field-name)
- field-value))
+ field-value))
(`(optional-field (field-name ,field-name))
(list field-name ""))))
@@ -634,12 +634,12 @@ For example,
(cond
((string-match "([^<]*)<([^>]*)>" address)
=> (lambda (match-record)
- (let ((name (string-trim-both (match:substring match-record 1)))
- (address (match:substring match-record 2)))
- (if (string-null? name)
- `((address . ,address))
- `((name . ,name)
- (address . ,address))))))
+ (let ((name (string-trim-both (match:substring match-record 1)))
+ (address (match:substring match-record 2)))
+ (if (string-null? name)
+ `((address . ,address))
+ `((name . ,name)
+ (address . ,address))))))
(else `((address . ,address)))))
(define interpret-address
@@ -658,50 +658,50 @@ message. Else, return a single <mime-entity> record."
(case (assoc-ref content-type 'type)
((multipart)
(map parse-mime-entity
- (body->mime-entities body (assoc-ref content-type 'boundary))))
+ (body->mime-entities body (assoc-ref content-type 'boundary))))
((text)
(string-trim-both
- (decode-body body (assoc-ref headers 'content-transfer-encoding)
- (assoc-ref content-type 'charset))))
+ (decode-body body (assoc-ref headers 'content-transfer-encoding)
+ (assoc-ref content-type 'charset))))
(else (decode-body body (assoc-ref headers 'content-transfer-encoding))))))
(define (add-default-headers headers)
;; Default Content-Type and Content-Transfer-Encoding headers as
;; specified in RFC2045
(let ((default-headers
- (acons* 'content-type '((type . text)
- (subtype . plain)
- ;; UTF-8 is specified as the default
- ;; charset in RFC6657
- (charset . "utf-8"))
- 'content-transfer-encoding '#{7bit}#)))
+ (acons* 'content-type '((type . text)
+ (subtype . plain)
+ ;; UTF-8 is specified as the default
+ ;; charset in RFC6657
+ (charset . "utf-8"))
+ 'content-transfer-encoding '#{7bit}#)))
(append (alist-delete* (append (if (assoc-ref headers 'content-type)
- (list 'content-type) (list))
- (if (assoc-ref headers 'content-transfer-encoding)
- (list 'content-transfer-encoding) (list)))
- default-headers)
- headers)))
+ (list 'content-type) (list))
+ (if (assoc-ref headers 'content-transfer-encoding)
+ (list 'content-transfer-encoding) (list)))
+ default-headers)
+ headers)))
(define (parse-mime-entity text)
(let-values (((headers body) (email->headers+body text)))
(let ((headers
- (pre-post-order
- (peg:tree
- (match-pattern mime-entity-fields text))
- `((content . ,post-process-content-type)
- (encoding . ,post-process-content-transfer-encoding)
- (disposition . ,post-process-content-disposition)
- (optional-field . ,post-process-optional-field)
- (mime-entity-fields . ,(lambda (_ . mime-entity-fields)
- (add-default-headers
- (map (match-lambda
- ((mime-entity-field value)
- (cons mime-entity-field value))
- ((mime-entity-field . values)
- (cons mime-entity-field values)))
- mime-entity-fields))))
- (*text* . ,(lambda (_ text) text))
- (*default* . ,(lambda tree tree))))))
+ (pre-post-order
+ (peg:tree
+ (match-pattern mime-entity-fields text))
+ `((content . ,post-process-content-type)
+ (encoding . ,post-process-content-transfer-encoding)
+ (disposition . ,post-process-content-disposition)
+ (optional-field . ,post-process-optional-field)
+ (mime-entity-fields . ,(lambda (_ . mime-entity-fields)
+ (add-default-headers
+ (map (match-lambda
+ ((mime-entity-field value)
+ (cons mime-entity-field value))
+ ((mime-entity-field . values)
+ (cons mime-entity-field values)))
+ mime-entity-fields))))
+ (*text* . ,(lambda (_ text) text))
+ (*default* . ,(lambda tree tree))))))
(make-mime-entity headers (parse-email-body headers body)))))
(define (parse-email email)
@@ -719,39 +719,39 @@ list of header keys and values."
(peg:tree
(match-pattern fields headers))
`((date-time . ,(lambda node
- (match-let
- ((`((day ,day) (month ,month) (year ,year)
- (hours ,hours) (minutes ,minutes) (seconds ,seconds)
- (zone-sign ,zone-sign) (zone-hours ,zone-hours) (zone-minutes ,zone-minutes))
- (flatten-and-filter
- '(day month year hours minutes seconds
- zone-sign zone-hours zone-minutes)
- node)))
- (make-date 0
- (string->number seconds)
- (string->number minutes)
- (string->number hours)
- (string->number day)
- (1+ (list-index
- (cut equal? <> month)
- (list "Jan" "Feb" "Mar" "Apr" "May" "Jun"
- "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")))
- (string->number year)
- (* (case (string->symbol zone-sign)
- ((+) 1)
- ((-) -1))
- (+ (* 60 60 (string->number zone-hours))
- (* 60 (string->number zone-minutes))))))))
+ (match-let
+ ((`((day ,day) (month ,month) (year ,year)
+ (hours ,hours) (minutes ,minutes) (seconds ,seconds)
+ (zone-sign ,zone-sign) (zone-hours ,zone-hours) (zone-minutes ,zone-minutes))
+ (flatten-and-filter
+ '(day month year hours minutes seconds
+ zone-sign zone-hours zone-minutes)
+ node)))
+ (make-date 0
+ (string->number seconds)
+ (string->number minutes)
+ (string->number hours)
+ (string->number day)
+ (1+ (list-index
+ (cut equal? <> month)
+ (list "Jan" "Feb" "Mar" "Apr" "May" "Jun"
+ "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")))
+ (string->number year)
+ (* (case (string->symbol zone-sign)
+ ((+) 1)
+ ((-) -1))
+ (+ (* 60 60 (string->number zone-hours))
+ (* 60 (string->number zone-minutes))))))))
(orig-date . ,(lambda (_ date) (list 'date date)))
(angle-addr . ,extract-value)
(mailbox . ,(match-lambda*
- (`(mailbox (display-name ,name) ,address)
- `((name . ,(decode-mime-encoded-word
- (string-trim-both name)))
- (address . ,address)))
- (`(mailbox ,address)
- `((address . ,(string-trim-both address))))
- (_ (error "Failed to parse mailbox"))))
+ (`(mailbox (display-name ,name) ,address)
+ `((name . ,(decode-mime-encoded-word
+ (string-trim-both name)))
+ (address . ,address)))
+ (`(mailbox ,address)
+ `((address . ,(string-trim-both address))))
+ (_ (error "Failed to parse mailbox"))))
(address-list *macro* . ,macro-process-address-list)
(mailbox-list *macro* . ,macro-process-address-list)
(optional-field . ,post-process-optional-field)
@@ -760,45 +760,45 @@ list of header keys and values."
(encoding . ,post-process-content-transfer-encoding)
(disposition . ,post-process-content-disposition)
(fields . ,(lambda (_ . fields)
- (add-default-headers
- (filter-map (match-lambda
- (('trace . _) #f)
- ((field value)
- (cons field value))
- ((field . values)
- (cons field values))
- (_ #f))
- fields))))
+ (add-default-headers
+ (filter-map (match-lambda
+ (('trace . _) #f)
+ ((field value)
+ (cons field value))
+ ((field . values)
+ (cons field values))
+ (_ #f))
+ fields))))
(*text* . ,extract-value)
(*default* . ,(lambda tree tree)))))
(define* (decode-body body encoding #:optional charset)
(let ((octets
- (case encoding
- ((base64)
- (base64-decode
- (string-filter
- (char-set-union
- (ucs-range->char-set (char->integer #\a) (1+ (char->integer #\z)))
- (ucs-range->char-set (char->integer #\A) (1+ (char->integer #\Z)))
- (ucs-range->char-set (char->integer #\0) (1+ (char->integer #\9)))
- (char-set #\+ #\/ #\=))
- body)))
- ((quoted-printable) (quoted-printable-decode body))
- ((#{7bit}# #{8bit}# binary) body)
- (else (error "Body decoding failed. Unknown encoding" encoding)))))
+ (case encoding
+ ((base64)
+ (base64-decode
+ (string-filter
+ (char-set-union
+ (ucs-range->char-set (char->integer #\a) (1+ (char->integer #\z)))
+ (ucs-range->char-set (char->integer #\A) (1+ (char->integer #\Z)))
+ (ucs-range->char-set (char->integer #\0) (1+ (char->integer #\9)))
+ (char-set #\+ #\/ #\=))
+ body)))
+ ((quoted-printable) (quoted-printable-decode body))
+ ((#{7bit}# #{8bit}# binary) body)
+ (else (error "Body decoding failed. Unknown encoding" encoding)))))
(if charset
- (case encoding
- ((base64 quoted-printable) (bytevector->string octets charset))
- ((#{7bit}# #{8bit}# binary) octets))
- octets)))
+ (case encoding
+ ((base64 quoted-printable) (bytevector->string octets charset))
+ ((#{7bit}# #{8bit}# binary) octets))
+ octets)))
(define (read-next-email-in-mbox port)
;; Read and discard From_ line
(get-line-with-delimiter port)
;; Read the actual email
(read-while port get-line-with-delimiter
- (negate (cut string-prefix? "From " <>))))
+ (negate (cut string-prefix? "From " <>))))
(define (mbox->emails port)
(read-objects read-next-email-in-mbox port))
diff --git a/email/quoted-printable.scm b/email/quoted-printable.scm
index d084a7e..b6f4c54 100644
--- a/email/quoted-printable.scm
+++ b/email/quoted-printable.scm
@@ -23,8 +23,8 @@
#:use-module (ice-9 match)
#:use-module (srfi srfi-26)
#:export (quoted-printable-decode
- quoted-printable-encode
- q-encoding-decode))
+ quoted-printable-encode
+ q-encoding-decode))
;; TODO: Error out on invalid quoted-printable input
(define quoted-printable-decode
@@ -33,30 +33,30 @@
(call-with-input-string str quoted-printable-decode))
(((? port? in))
(let-values (((out get-bytevector)
- (open-bytevector-output-port)))
+ (open-bytevector-output-port)))
(call-with-port
- out (lambda (out)
- (quoted-printable-decode in out)
- (get-bytevector)))))
+ out (lambda (out)
+ (quoted-printable-decode in out)
+ (get-bytevector)))))
(((? port? in) (? port? out))
(let ((c (read-char in)))
(cond
- ((eof-object? c) out)
- ((char=? c #\=)
- ;; TODO: Support "\r\n" line ending
- (let ((c1 (read-char in)))
- (unless (char=? c1 #\Newline)
- (let ((c2 (read-char in)))
- (put-u8 out (string->number (string c1 c2) 16)))))
- (quoted-printable-decode in out))
- (else (put-u8 out (char->integer c))
- (quoted-printable-decode in out)))))))
+ ((eof-object? c) out)
+ ((char=? c #\=)
+ ;; TODO: Support "\r\n" line ending
+ (let ((c1 (read-char in)))
+ (unless (char=? c1 #\Newline)
+ (let ((c2 (read-char in)))
+ (put-u8 out (string->number (string c1 c2) 16)))))
+ (quoted-printable-decode in out))
+ (else (put-u8 out (char->integer c))
+ (quoted-printable-decode in out)))))))
(define quoted-printable-encode
(match-lambda*
(((? bytevector? bv))
(call-with-port (open-bytevector-input-port bv)
- quoted-printable-encode))
+ quoted-printable-encode))
(((? port? in))
(call-with-output-string
(cut quoted-printable-encode in <>)))
@@ -64,24 +64,24 @@
(quoted-printable-encode in out 76))
(((? port? in) (? port? out) (? integer? number-of-chars-left-on-this-line))
(let ((x (get-u8 in))
- (put-into-output
- (lambda (str)
- (let* ((len (string-length str))
- (break-line? (<= number-of-chars-left-on-this-line len)))
- (put-string
- out (string-append (if break-line? "=\n" "") str))
- (if break-line?
- (- 76 len)
- (- number-of-chars-left-on-this-line len))))))
+ (put-into-output
+ (lambda (str)
+ (let* ((len (string-length str))
+ (break-line? (<= number-of-chars-left-on-this-line len)))
+ (put-string
+ out (string-append (if break-line? "=\n" "") str))
+ (if break-line?
+ (- 76 len)
+ (- number-of-chars-left-on-this-line len))))))
(unless (eof-object? x)
- (let ((c (integer->char x)))
- (quoted-printable-encode
- in out
- (put-into-output
- (if (char-set-contains?
- (char-set-delete char-set:ascii #\newline #\return) c)
- (string c)
- (format #f "=~:@(~2,'0x~)" x))))))))))
+ (let ((c (integer->char x)))
+ (quoted-printable-encode
+ in out
+ (put-into-output
+ (if (char-set-contains?
+ (char-set-delete char-set:ascii #\newline #\return) c)
+ (string c)
+ (format #f "=~:@(~2,'0x~)" x))))))))))
(define (q-encoding-decode str)
(quoted-printable-decode
diff --git a/email/utils.scm b/email/utils.scm
index 7d51ebb..e942fc2 100644
--- a/email/utils.scm
+++ b/email/utils.scm
@@ -23,18 +23,18 @@
#:use-module (ice-9 textual-ports)
#:use-module (rnrs io simple)
#:export (get-line-with-delimiter
- read-objects
- read-while
- acons*
- alist-delete*))
+ read-objects
+ read-while
+ acons*
+ alist-delete*))
(define (read-objects read-proc port)
"Read all objects using READ-PROC from PORT and return them as a
list."
(let ((x (read-proc port)))
(if (eof-object? x)
- (list)
- (cons x (read-objects read-proc port)))))
+ (list)
+ (cons x (read-objects read-proc port)))))
(define* (read-while port read-proc pred)
"Read from PORT using READ-PROC while PRED returns #t. READ-PROC is
@@ -45,8 +45,8 @@ string returned by READ-PROC as argument."
(cond
((eof-object? x) x)
((pred x)
- (put-string output x)
- (read-while-loop output))
+ (put-string output x)
+ (read-while-loop output))
(#t (unget-string port x)))))
(let ((str (call-with-output-string read-while-loop)))
@@ -57,8 +57,8 @@ string returned by READ-PROC as argument."
delimiting linefeed character."
(let ((line (get-line port)))
(if (eof-object? line)
- line
- (string-append line "\n"))))
+ line
+ (string-append line "\n"))))
(define acons*
(match-lambda*
@@ -72,24 +72,24 @@ delimiting linefeed character."
"Return a list containing all elements of ALIST whose keys are not a
member of KEYS."
(filter (match-lambda
- ((key . _)
- (not (member key keys))))
- alist))
+ ((key . _)
+ (not (member key keys))))
+ alist))
(define (cg-string-ci pat accum)
(syntax-case pat ()
((pat-str-syntax) (string? (syntax->datum #'pat-str-syntax))
(let ((pat-str (syntax->datum #'pat-str-syntax)))
(let ((plen (string-length pat-str)))
- #`(lambda (str len pos)
- (let ((end (+ pos #,plen)))
- (and (<= end len)
- (string-ci= str #,pat-str pos end)
- #,(case accum
- ((all) #`(list end (list 'cg-string #,pat-str)))
- ((name) #`(list end 'cg-string))
- ((body) #`(list end #,pat-str))
- ((none) #`(list end '()))
- (else (error "bad accum" accum)))))))))))
+ #`(lambda (str len pos)
+ (let ((end (+ pos #,plen)))
+ (and (<= end len)
+ (string-ci= str #,pat-str pos end)
+ #,(case accum
+ ((all) #`(list end (list 'cg-string #,pat-str)))
+ ((name) #`(list end 'cg-string))
+ ((body) #`(list end #,pat-str))
+ ((none) #`(list end '()))
+ (else (error "bad accum" accum)))))))))))
(add-peg-compiler! 'string-ci cg-string-ci)