Use new sieve-register style.
(sieve-preprocess-arguments): New function. Preprocess and group arguments into optional and positional types. (sieve-parse-arguments): New function. Parses arguments to an action or a test. (sieve-register-action,sieve-register-test): Rewritten.
Showing
1 changed file
with
120 additions
and
89 deletions
1 | #! %BINDIR%/guimb --source | 1 | #! %BINDIR%/guimb --source |
2 | # Emacs, its -*- scheme -*- | ||
2 | !# | 3 | !# |
3 | ;;;; GNU mailutils - a suite of utilities for electronic mail | 4 | ;;;; GNU mailutils - a suite of utilities for electronic mail |
4 | ;;;; Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. | 5 | ;;;; Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. |
... | @@ -130,11 +131,19 @@ | ... | @@ -130,11 +131,19 @@ |
130 | (>= end (1- input-length)) | 131 | (>= end (1- input-length)) |
131 | (not (char-numeric? | 132 | (not (char-numeric? |
132 | (string-ref input-line end)))) | 133 | (string-ref input-line end)))) |
133 | end))) | 134 | |
135 | (cond | ||
136 | ((char-numeric? (string-ref input-line end)) | ||
137 | (1+ end)) | ||
138 | (else | ||
139 | end))))) | ||
134 | (num (string->number (substring input-line start end))) | 140 | (num (string->number (substring input-line start end))) |
135 | (q (string-ref input-line end)) | 141 | (q (if (< end input-length) |
142 | (string-ref input-line end) | ||
143 | #f)) | ||
136 | (k 1)) | 144 | (k 1)) |
137 | (case q | 145 | (case q |
146 | ((#f) #f) ;; nothing | ||
138 | ((#\K) | 147 | ((#\K) |
139 | (set! end (1+ end)) | 148 | (set! end (1+ end)) |
140 | (set! k 1024)) | 149 | (set! k 1024)) |
... | @@ -145,11 +154,8 @@ | ... | @@ -145,11 +154,8 @@ |
145 | (set! end (1+ end)) | 154 | (set! end (1+ end)) |
146 | (set! k 1073741824)) | 155 | (set! k 1073741824)) |
147 | (else | 156 | (else |
148 | (cond | 157 | (if (not (delimiter? q)) |
149 | ((char-numeric? q) | 158 | (lex-error "Unknown qualifier (" q ")")))) |
150 | (set! end (1+ end))) | ||
151 | ((not (delimiter? q)) | ||
152 | (lex-error "Unknown qualifier (" q ")"))))) | ||
153 | (set! input-index end) | 159 | (set! input-index end) |
154 | (cons 'number (* num k)))) | 160 | (cons 'number (* num k)))) |
155 | (else | 161 | (else |
... | @@ -410,7 +416,8 @@ | ... | @@ -410,7 +416,8 @@ |
410 | (define (sieve-find-test name) | 416 | (define (sieve-find-test name) |
411 | (sieve-syntax-table-lookup sieve-test-table name)) | 417 | (sieve-syntax-table-lookup sieve-test-table name)) |
412 | 418 | ||
413 | (define (sieve-register-test name function opt-arg-list req-arg-list) | 419 | (define (sieve-register-test name function req-arg-list opt-arg-list) |
420 | (DEBUG 100 "sieve-register-test" name req-arg-list opt-arg-list) | ||
414 | (cond | 421 | (cond |
415 | ((not (list? opt-arg-list)) | 422 | ((not (list? opt-arg-list)) |
416 | (lex-error "sieve-register-test: opt-arg-list must be a list")) | 423 | (lex-error "sieve-register-test: opt-arg-list must be a list")) |
... | @@ -427,10 +434,14 @@ | ... | @@ -427,10 +434,14 @@ |
427 | (list name function opt-arg-list req-arg-list))))))) | 434 | (list name function opt-arg-list req-arg-list))))))) |
428 | 435 | ||
429 | 436 | ||
437 | ;;; sieve-preprocess-arguments: Preprocess and group the arguments. Returns | ||
438 | ;;; a cons whose car is a list of all optional arguments, and the cdr is | ||
439 | ;;; a list of the rest of the arguments. | ||
440 | ;;; | ||
430 | ;;; arguments = *argument [test / test-list] | 441 | ;;; arguments = *argument [test / test-list] |
431 | ;;; argument = string-list / number / tag | 442 | ;;; argument = string-list / number / tag |
432 | 443 | ||
433 | (define (sieve-parse-arguments tag-gram) | 444 | (define (sieve-preprocess-arguments tag-gram) |
434 | (do ((opt-list '()) ;; List of optional arguments (tags) | 445 | (do ((opt-list '()) ;; List of optional arguments (tags) |
435 | (arg-list '()) ;; List of positional arguments | 446 | (arg-list '()) ;; List of positional arguments |
436 | (last-tag #f) ;; Description of the last tag from tag-gram | 447 | (last-tag #f) ;; Description of the last tag from tag-gram |
... | @@ -472,17 +483,78 @@ | ... | @@ -472,17 +483,78 @@ |
472 | (else | 483 | (else |
473 | (set! arg-list (append arg-list (list token))))) | 484 | (set! arg-list (append arg-list (list token))))) |
474 | #f) | 485 | #f) |
475 | ((delimiter token #\[) ;;FIXME: tags are not allowed to take | 486 | ((delimiter token #\[) |
476 | ;;string-list arguments. | ||
477 | (set! state 'arg) | ||
478 | (putback-token) | 487 | (putback-token) |
479 | (set! arg-list (append arg-list | 488 | (cond |
480 | (list (require-string-list)))) | 489 | ((and (eq? state 'opt) (pair? last-tag)) |
481 | #f) | 490 | (cond |
491 | ((cdr last-tag) | ||
492 | (if (not (eq? (cdr last-tag) 'string-list)) | ||
493 | (syntax-error | ||
494 | "Tag :" (car last-tag) " takes string list argument")) | ||
495 | (set! opt-list (append opt-list (list (require-string-list)))) | ||
496 | (set! last-tag #f)) | ||
497 | (else | ||
498 | (set! state 'arg) | ||
499 | (set! arg-list (append arg-list (list (require-string-list))))))) | ||
500 | (else | ||
501 | (set! arg-list (append arg-list (list (require-string-list)))))) | ||
502 | #f) | ||
482 | (else | 503 | (else |
483 | #t)) | 504 | #t)) |
484 | (cons opt-list arg-list)))) | 505 | (cons opt-list arg-list)))) |
485 | 506 | ||
507 | ;;; sieve-parse-arguments: Parse the arguments to a test or an action. | ||
508 | ;;; ENTRY is the syntax table entry to guide the parsing | ||
509 | ;;; | ||
510 | (define (sieve-parse-arguments ident entry) | ||
511 | (DEBUG 100 "sieve-parse-arguments" entry) | ||
512 | (let ((arg-list (sieve-preprocess-arguments (car (cdr entry))))) | ||
513 | ;; Process positional arguments | ||
514 | (do ((expect (car (cdr (cdr entry))) (cdr expect)) | ||
515 | (argl (cdr arg-list) (cdr argl)) | ||
516 | (n 1 (1+ n))) | ||
517 | ((cond | ||
518 | ((null? expect) | ||
519 | (if (not (null? argl)) | ||
520 | (syntax-error | ||
521 | "Too many positional arguments for " ident | ||
522 | " (bailed out at " (car argl) ")")) | ||
523 | #t) | ||
524 | ((null? argl) | ||
525 | (if (not (null? expect)) | ||
526 | (syntax-error | ||
527 | "Too few positional arguments for " ident)) | ||
528 | #t) | ||
529 | (else #f)) #f) | ||
530 | (let ((expect-type (car expect)) | ||
531 | (arg (car argl))) | ||
532 | (cond | ||
533 | ((and (eq? expect-type 'string-list) | ||
534 | (eq? (car arg) 'string)) | ||
535 | ;; Coerce string to string-list | ||
536 | (sieve-exp-append (list 'list (cdr arg)))) | ||
537 | ((eq? expect-type (car arg)) | ||
538 | (if (eq? expect-type 'string-list) | ||
539 | (sieve-exp-append (append (list 'list) (cdr arg))) | ||
540 | (sieve-exp-append (cdr arg)))) | ||
541 | (else | ||
542 | (syntax-error | ||
543 | "Type mismatch in argument " n " to " (cdr ident) | ||
544 | "; expected " expect-type ", but got " (car arg)))))) | ||
545 | ;; Process optional arguments (tags). | ||
546 | ;; They have already been tested | ||
547 | (for-each | ||
548 | (lambda (tag) | ||
549 | (sieve-exp-append (cond | ||
550 | ((eq? (car tag) 'tag) | ||
551 | (string->symbol (string-append "#:" (cdr tag)))) | ||
552 | ((eq? (car tag) 'string-list) | ||
553 | (append (list 'list) (cdr tag))) | ||
554 | (else | ||
555 | (cdr tag))))) | ||
556 | (car arg-list)))) | ||
557 | |||
486 | ;;; test-list = "(" test *("," test) ")" | 558 | ;;; test-list = "(" test *("," test) ")" |
487 | (define (sieve-parse-test-list) | 559 | (define (sieve-parse-test-list) |
488 | (do ((token (sieve-parse-test) (sieve-parse-test))) | 560 | (do ((token (sieve-parse-test) (sieve-parse-test))) |
... | @@ -527,50 +599,8 @@ | ... | @@ -527,50 +599,8 @@ |
527 | (if (not test) | 599 | (if (not test) |
528 | (syntax-error "Unknown test name: " (cdr ident))) | 600 | (syntax-error "Unknown test name: " (cdr ident))) |
529 | (putback-token) | 601 | (putback-token) |
530 | (let ((arg-list (sieve-parse-arguments (car (cdr test))))) | 602 | (sieve-exp-append (car test)) |
531 | (sieve-exp-append (car test)) | 603 | (sieve-parse-arguments (cdr ident) test)))))) |
532 | ;; Process positional arguments | ||
533 | (do ((expect (car (cdr (cdr test))) (cdr expect)) | ||
534 | (argl (cdr arg-list) (cdr argl)) | ||
535 | (n 1 (1+ n))) | ||
536 | ((cond | ||
537 | ((null? expect) | ||
538 | (if (not (null? argl)) | ||
539 | (syntax-error | ||
540 | "Too many positional arguments for " ident | ||
541 | " (bailed out at " (car argl) ")")) | ||
542 | #t) | ||
543 | ((null? argl) | ||
544 | (if (not (null? expect)) | ||
545 | (syntax-error | ||
546 | "Too few positional arguments for " ident)) | ||
547 | #t) | ||
548 | (else #f)) #f) | ||
549 | (let ((expect-type (car expect)) | ||
550 | (arg (car argl))) | ||
551 | (cond | ||
552 | ((and (eq? expect-type 'string-list) | ||
553 | (eq? (car arg) 'string)) | ||
554 | ;; Coerce string to string-list | ||
555 | (sieve-exp-append (list 'list (cdr arg)))) | ||
556 | ((eq? expect-type (car arg)) | ||
557 | (if (eq? expect-type 'string-list) | ||
558 | (sieve-exp-append (append (list 'list) (cdr arg))) | ||
559 | (sieve-exp-append (cdr arg)))) | ||
560 | (else | ||
561 | (syntax-error | ||
562 | "Type mismatch in argument " n " to " (cdr ident) | ||
563 | "; expected " expect-type ", but got " (car arg)))))) | ||
564 | ;; Process optional arguments (tags). | ||
565 | ;; They have already been tested | ||
566 | (for-each | ||
567 | (lambda (tag) | ||
568 | (sieve-exp-append (if (eq? (car tag) 'tag) | ||
569 | (string->symbol | ||
570 | (string-append "#:" (cdr tag))) | ||
571 | (cdr tag)))) | ||
572 | (car arg-list)) | ||
573 | )))))) | ||
574 | (sieve-exp-finish)) | 604 | (sieve-exp-finish)) |
575 | current-token) | 605 | current-token) |
576 | 606 | ||
... | @@ -664,46 +694,47 @@ | ... | @@ -664,46 +694,47 @@ |
664 | 694 | ||
665 | ;;; Actions | 695 | ;;; Actions |
666 | 696 | ||
667 | ;;; Each entry is: (list ACTION-NAME FUNCTION ARG-LIST) | 697 | ;;; Each entry is: (list NAME FUNCTION OPT-ARG-LIST REQ-ARG-LIST) |
668 | ;;; ARG-LIST is a list of argument types | 698 | ;;; NAME is a string representing the action name, |
699 | ;;; FUNCTION is a corresponding function: | ||
700 | ;;; (define (action-foo [arg [arg...]] . opt-args) | ||
701 | ;;; notice, that its name must begin with "action-" | ||
702 | ;;; OPT-ARG-LIST is a list of optional arguments (tags), | ||
703 | ;;; REQ-ARG-LIST is a list of required (positional) arguments | ||
669 | (define sieve-action-table '()) | 704 | (define sieve-action-table '()) |
670 | 705 | ||
671 | (define (sieve-find-action name) | 706 | (define (sieve-find-action name) |
672 | (sieve-syntax-table-lookup sieve-action-table name)) | 707 | (sieve-syntax-table-lookup sieve-action-table name)) |
673 | 708 | ||
674 | (define (sieve-register-action name proc . arg-list) | 709 | (define (sieve-register-action name function req-arg-list opt-arg-list) |
675 | (if (not (sieve-find-action name)) | 710 | (cond |
676 | (set! sieve-action-table (append sieve-action-table | 711 | ((not (list? opt-arg-list)) |
677 | (list | 712 | (lex-error "sieve-register-action: opt-arg-list must be a list")) |
678 | (append | 713 | ((not (list? req-arg-list)) |
679 | (list name proc) arg-list)))))) | 714 | (lex-error "sieve-register-action: req-arg-list must be a list")) |
715 | ((not (or (eq? function #f) | ||
716 | (eq? function #t) | ||
717 | (procedure? function))) | ||
718 | (lex-error "sieve-register-action: bad type for function" function)) | ||
719 | (else | ||
720 | (set! sieve-action-table | ||
721 | (append sieve-action-table | ||
722 | (list | ||
723 | (list name function opt-arg-list req-arg-list))))))) | ||
680 | 724 | ||
681 | (define (sieve-parse-action) | 725 | (define (sieve-parse-action) |
682 | (let* ((name (cdr current-token)) | 726 | (let* ((name (cdr current-token)) |
683 | (descr (sieve-find-action name))) | 727 | (descr (sieve-find-action name))) |
684 | (cond | 728 | (cond |
685 | (descr | 729 | (descr |
686 | (if (car descr) | 730 | (cond |
687 | (sieve-exp-begin (car descr))) | 731 | ((car descr) |
688 | (do ((arg (cdr descr) (cdr arg))) | 732 | (sieve-exp-begin (car descr)) |
689 | ((null? arg) #f) | 733 | (sieve-parse-arguments name descr) |
690 | (read-token) | 734 | (require-semicolon 'dont-read) |
691 | (case (car arg) | 735 | (sieve-exp-finish)) |
692 | ((string) | 736 | (else |
693 | (require-string 'dont-read)) | 737 | (require-semicolon)))) |
694 | ((string-list) | ||
695 | (require-string-list 'dont-read)) | ||
696 | ((number) | ||
697 | (require-number 'dont-read)) | ||
698 | ((tag) | ||
699 | (require-tag 'dont-read)) | ||
700 | (else | ||
701 | (syntax-error "Malformed table entry for " name " :" (car arg)))) | ||
702 | (if (car descr) | ||
703 | (sieve-exp-append (cdr current-token)))) | ||
704 | (require-semicolon) | ||
705 | (if (car descr) | ||
706 | (sieve-exp-finish))) | ||
707 | (else | 738 | (else |
708 | (syntax-error "Unknown identifier: " name))))) | 739 | (syntax-error "Unknown identifier: " name))))) |
709 | 740 | ||
... | @@ -853,7 +884,7 @@ | ... | @@ -853,7 +884,7 @@ |
853 | (display (string-append | 884 | (display (string-append |
854 | ";;;; A Guile mailbox parser made from " filename) port) | 885 | ";;;; A Guile mailbox parser made from " filename) port) |
855 | (newline port) | 886 | (newline port) |
856 | (display ";;;; by sieve.scm, GNU mailutils (0.0.9)" port) | 887 | (display ";;;; by sieve.scm, GNU %PACKAGE% %VERSION%" port) |
857 | (newline port) | 888 | (newline port) |
858 | 889 | ||
859 | (display "(define sieve-parser #f)" port) | 890 | (display "(define sieve-parser #f)" port) | ... | ... |
-
Please register or sign in to post a comment