Commit 53b92684 53b92684a5ab835cbcf68296ecd4b0a2b8649cd5 by Sergey Poznyakoff

Cleaned up the source.

1 parent f6ff2719
1 #! %BINDIR%/guimb --source 1 #! %GUILE_BINDIR%/guile -s
2 # Emacs, its -*- scheme -*- 2 # Emacs, its -*- scheme -*-
3 !# 3 !#
4 ;;;; GNU mailutils - a suite of utilities for electronic mail 4 ;;;; GNU mailutils - a suite of utilities for electronic mail
...@@ -21,19 +21,21 @@ ...@@ -21,19 +21,21 @@
21 21
22 ;;;; This is a Sieve to Scheme translator. 22 ;;;; This is a Sieve to Scheme translator.
23 ;;;; 23 ;;;;
24 ;;;; To convert a sieve script into equivalent Scheme program, executable 24 ;;;; To convert a sieve script into equivalent Scheme program, run:
25 ;;;; by guimb, run:
26 ;;;; 25 ;;;;
27 ;;;; guile -s sieve.scm --file <sieve-script-name> --output <output-file-name> 26 ;;;; guile -s sieve.scm --file <sieve-script-name> --output <output-file-name>
28 ;;;; 27 ;;;;
29 ;;;; To compile and execute a sieve script upon a mailbox, run: 28 ;;;; To compile and execute a sieve script upon a mailbox, run:
30 ;;;; 29 ;;;;
31 ;;;; guimb -f sieve.scm -{ --file <sieve-script-name> -} --mailbox ~/mbox 30 ;;;; guile -s sieve.scm --file <sieve-script-name> [mailbox-name]
31 ;;;; or
32 ;;;; guimb [--mailbox mailbox-name] -s sieve.scm --file <sieve-script-name>
32 33
33 (define sieve-debug 0) 34 (define sieve-debug 0)
34 (define sieve-parser #t) 35 (define sieve-parser #t)
35 (define sieve-libdir "%LIBDIR%") 36 (define sieve-libdir "%LIBDIR%")
36 (define sieve-load-files '()) 37 (define sieve-load-files '())
38 (define sieve-script-args '())
37 39
38 (define error-count 0) 40 (define error-count 0)
39 (define current-token #f) 41 (define current-token #f)
...@@ -374,65 +376,81 @@ ...@@ -374,65 +376,81 @@
374 376
375 ;;;; 377 ;;;;
376 378
379 ;;; Syntax tables.
380 ;;; A syntax table is a list of
381 ;;; Each entry is: (list NAME FUNCTION OPT-ARG-LIST REQ-ARG-LIST)
382 ;;; NAME is a string representing the input language keyword,
383 ;;; FUNCTION is a corresponding function:
384 ;;; (define (foo [arg [arg...]] . opt-args)
385 ;;; OPT-ARG-LIST is a list of optional arguments (tags),
386 ;;; REQ-ARG-LIST is a list of required (positional) arguments
387
377 (define (sieve-syntax-table-lookup table name) 388 (define (sieve-syntax-table-lookup table name)
378 (call-with-current-continuation 389 (let ((entry (assoc name table)))
379 (lambda (exit) 390 (if entry
380 (for-each (lambda (x) 391 (cdr entry)
381 (if (string=? (car x) name)
382 (exit (cdr x))))
383 table)
384 #f))) 392 #f)))
385 393
394 (define-macro (sieve-syntax-table-add table name function req-arg-list opt-arg-list)
395 `(cond
396 ((not (list? ,opt-arg-list))
397 (lex-error "sieve-syntax-table-add: opt-arg-list must be a list"))
398 ((not (list? ,req-arg-list))
399 (lex-error "sieve-syntax-table-add: req-arg-list must be a list"))
400 ((not (or (eq? ,function #f)
401 (eq? ,function #t)
402 (procedure? ,function)))
403 (lex-error "sieve-syntax-table-add: bad type for function" ,function))
404 (else
405 (set! ,table
406 (append ,table
407 (list
408 (list ,name ,function ,opt-arg-list ,req-arg-list)))))))
409
410 ;;;;
411
412 ;;;; Available syntax tables.
413
386 ;;;; Comparators 414 ;;;; Comparators
387 415
388 ;;; Each entry is (list COMP-NAME COMP-FUNCTION) 416 ;;; Syntax table for comparators. The opt-arg-list and req-arg-list have
417 ;;; no meaning for comparators, so they are ignored. The handler function
418 ;;; names must start with "comparator-"
389 (define sieve-comparator-table '()) 419 (define sieve-comparator-table '())
390 420
391 (define (sieve-find-comparator name) 421 (define (sieve-find-comparator name)
392 (sieve-syntax-table-lookup sieve-comparator-table name)) 422 (sieve-syntax-table-lookup sieve-comparator-table name))
393 423
394 (define (sieve-register-comparator name function) 424 (define (sieve-register-comparator name function)
395 (if (not (or (eq? function #f) 425 (sieve-syntax-table-add sieve-comparator-table name function '() '()))
396 (eq? function #t)
397 (procedure? function)))
398 (lex-error "sieve-register-comparator: bad type for function"
399 function))
400 (set! sieve-comparator-table
401 (append sieve-comparator-table (list
402 (cons name function)))))
403 426
427 ;;;; Sieve Tests
404 428
405 ;;;; Command parsers 429 ;;; Syntax table for tests. Function names must start with "test-"
406
407 ;;; Each entry is: (list NAME FUNCTION OPT-ARG-LIST REQ-ARG-LIST)
408 ;;; OPT-ARG-LIST is a list of optional arguments (aka keywords, tags).
409 ;;; It consists of conses: (cons TAG-NAME FLAG) where FLAG is #t
410 ;;; if the tag requires an argument (e.g. :comparator <comp-name>),
411 ;;; and is #f otherwise.
412 ;;; REQ-ARG-LIST is a list of required (positional) arguments. It
413 ;;; is a list of argument types.
414 (define sieve-test-table '()) 430 (define sieve-test-table '())
415 431
416 (define (sieve-find-test name) 432 (define (sieve-find-test name)
417 (sieve-syntax-table-lookup sieve-test-table name)) 433 (sieve-syntax-table-lookup sieve-test-table name))
418 434
419 (define (sieve-register-test name function req-arg-list opt-arg-list) 435 (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) 436 (sieve-syntax-table-add sieve-test-table name function
421 (cond 437 req-arg-list opt-arg-list))
422 ((not (list? opt-arg-list))
423 (lex-error "sieve-register-test: opt-arg-list must be a list"))
424 ((not (list? req-arg-list))
425 (lex-error "sieve-register-test: req-arg-list must be a list"))
426 ((not (or (eq? function #f)
427 (eq? function #t)
428 (procedure? function)))
429 (lex-error "sieve-register-test: bad type for function" function))
430 (else
431 (set! sieve-test-table
432 (append sieve-test-table
433 (list
434 (list name function opt-arg-list req-arg-list)))))))
435 438
439 ;;;; Sieve Actions
440
441 ;;; Syntax table for actions. Function names start with "action-"
442 (define sieve-action-table '())
443
444 (define (sieve-find-action name)
445 (sieve-syntax-table-lookup sieve-action-table name))
446
447 (define (sieve-register-action name function req-arg-list opt-arg-list)
448 (sieve-syntax-table-add sieve-action-table name function
449 req-arg-list opt-arg-list))
450
451 ;;;;
452
453 ;;;; Command parsers
436 454
437 ;;; sieve-preprocess-arguments: Preprocess and group the arguments. Returns 455 ;;; 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 456 ;;; a cons whose car is a list of all optional arguments, and the cdr is
...@@ -555,6 +573,10 @@ ...@@ -555,6 +573,10 @@
555 (cdr tag))))) 573 (cdr tag)))))
556 (car arg-list)))) 574 (car arg-list))))
557 575
576 ;;;;
577
578 ;;;; Parser functions for tests
579
558 ;;; test-list = "(" test *("," test) ")" 580 ;;; test-list = "(" test *("," test) ")"
559 (define (sieve-parse-test-list) 581 (define (sieve-parse-test-list)
560 (do ((token (sieve-parse-test) (sieve-parse-test))) 582 (do ((token (sieve-parse-test) (sieve-parse-test)))
...@@ -692,35 +714,9 @@ ...@@ -692,35 +714,9 @@
692 (sieve-exp-finish) 714 (sieve-exp-finish)
693 (require-semicolon)) 715 (require-semicolon))
694 716
695 ;;; Actions 717 ;;;;
696
697 ;;; Each entry is: (list NAME FUNCTION OPT-ARG-LIST REQ-ARG-LIST)
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
704 (define sieve-action-table '())
705
706 (define (sieve-find-action name)
707 (sieve-syntax-table-lookup sieve-action-table name))
708 718
709 (define (sieve-register-action name function req-arg-list opt-arg-list) 719 ;;;; Parser functions for actions
710 (cond
711 ((not (list? opt-arg-list))
712 (lex-error "sieve-register-action: opt-arg-list must be a list"))
713 ((not (list? req-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)))))))
724 720
725 (define (sieve-parse-action) 721 (define (sieve-parse-action)
726 (let* ((name (cdr current-token)) 722 (let* ((name (cdr current-token))
...@@ -738,7 +734,9 @@ ...@@ -738,7 +734,9 @@
738 (else 734 (else
739 (syntax-error "Unknown identifier: " name))))) 735 (syntax-error "Unknown identifier: " name)))))
740 736
741 ;;;; Parser 737 ;;;;
738
739 ;;;; The parser
742 740
743 (define (sieve-parse-command) 741 (define (sieve-parse-command)
744 (DEBUG 10 "sieve-parse-command" current-token) 742 (DEBUG 10 "sieve-parse-command" current-token)
...@@ -829,6 +827,8 @@ ...@@ -829,6 +827,8 @@
829 (call-with-input-file filename sieve-parse-from-port)) 827 (call-with-input-file filename sieve-parse-from-port))
830 (lambda args args)))) 828 (lambda args args))))
831 829
830 ;;;;
831
832 ;;;; Code generator 832 ;;;; Code generator
833 833
834 (define sieve-exp '()) ;; Expression currently being built 834 (define sieve-exp '()) ;; Expression currently being built
...@@ -876,15 +876,18 @@ ...@@ -876,15 +876,18 @@
876 876
877 ;;; Save the program 877 ;;; Save the program
878 878
879 (define (sieve-save-program outfile) 879 (define (sieve-save-program outfile guimb-header)
880 (call-with-output-file 880 (call-with-output-file
881 outfile 881 outfile
882 (lambda (port) 882 (lambda (port)
883 (display "#! /home/gray/mailutils/guimb/guimb --source\n!#\n" port) 883 (display "#! " port)
884 (if guimb-header
885 (display "%BINDIR%/guimb -s\n" port)
886 (display "%GUILE_BINDIR%/guile -s\n" port))
884 (display (string-append 887 (display (string-append
885 ";;;; A Guile mailbox parser made from " filename) port) 888 "# Guile mailbox parser made from " filename) port)
886 (newline port) 889 (newline port)
887 (display ";;;; by sieve.scm, GNU %PACKAGE% %VERSION%" port) 890 (display "# by sieve.scm, GNU %PACKAGE% %VERSION%\n!#" port)
888 (newline port) 891 (newline port)
889 892
890 (display "(define sieve-parser #f)" port) 893 (display "(define sieve-parser #f)" port)
...@@ -894,6 +897,10 @@ ...@@ -894,6 +897,10 @@
894 (newline port) 897 (newline port)
895 898
896 (display (string-append 899 (display (string-append
900 "(define sieve-libdir \"" sieve-libdir "\")") port)
901 (newline port)
902
903 (display (string-append
897 "(load \"" sieve-libdir "/sieve-core.scm\")") port) 904 "(load \"" sieve-libdir "/sieve-core.scm\")") port)
898 (newline port) 905 (newline port)
899 (for-each 906 (for-each
...@@ -906,40 +913,28 @@ ...@@ -906,40 +913,28 @@
906 (newline port) 913 (newline port)
907 (display "(sieve-main)" port)))) 914 (display "(sieve-main)" port))))
908 915
916 ;;;;
917
909 ;;;; Main 918 ;;;; Main
910 919
911 (define filename #f) 920 (define filename #f)
912 (define output #f) 921 (define output #f)
922 (define guimb-header #f)
913 923
914 (define (sieve-usage) 924 (define (sieve-usage)
915 (display "usage: sieve.scm [OPTIONS]\n") 925 (display "usage: sieve.scm [OPTIONS][mailbox]\n")
916 (display "GNU sieve.scm -- compile a Sieve program into Scheme code\n") 926 (display "GNU sieve.scm -- compile a Sieve program into Scheme code\n")
917 (display "Options are:\n") 927 (display "Options are:\n")
918 (display " -f, --file FILENAME Set input file name\n") 928 (display " -f, --file FILENAME Set input file name\n")
919 (display " -o, --output FILENAME Set output file name\n") 929 (display " -o, --output FILENAME Set output file name\n")
920 (display " -L, --lib-dir DIRNAME Set sieve library directory name\n") 930 (display " -L, --lib-dir DIRNAME Set sieve library directory name\n")
921 (display " -d, --debug LEVEL Set debugging level\n") 931 (display " -g, --guimb Make output file executable for guimb\n")
932 (display " -d, --debug LEVEL Set debugging level\n\n")
933 (display "If -o option is not given, the compiled program is executed\n")
934 (display "immediately. It operates on the user system mailbox unless\n")
935 (display "mailbox is given in the command line.\n")
922 (exit 0)) 936 (exit 0))
923 937
924 (define (sieve-expand-filename name)
925 (let ((index (string-index name #\%)))
926 (if (or (not index) (= index (string-length name)))
927 name
928 (let ((ch (string-ref name (1+ index))))
929 (string-append
930 (make-shared-substring name 0 index)
931 (case ch
932 ((#\%)
933 "%")
934 ((#\u)
935 user-name)
936 ((#\h)
937 (passwd:dir (getpwnam user-name)))
938 (else
939 (make-shared-substring name index 2)))
940 (sieve-expand-filename
941 (make-shared-substring name (+ index 2))))))))
942
943 ;;; Parse command line 938 ;;; Parse command line
944 939
945 (use-modules (ice-9 getopt-long)) 940 (use-modules (ice-9 getopt-long))
...@@ -952,6 +947,7 @@ ...@@ -952,6 +947,7 @@
952 (value #t)) 947 (value #t))
953 (lib-dir (single-char #\L) 948 (lib-dir (single-char #\L)
954 (value #t)) 949 (value #t))
950 (guimb (single-char #\g))
955 (help (single-char #\h)))) 951 (help (single-char #\h))))
956 952
957 (define program-name (car (command-line))) 953 (define program-name (car (command-line)))
...@@ -969,28 +965,21 @@ ...@@ -969,28 +965,21 @@
969 (set! sieve-libdir (cdr x))) 965 (set! sieve-libdir (cdr x)))
970 ((output) 966 ((output)
971 (set! output (cdr x))) 967 (set! output (cdr x)))
968 ((guimb)
969 (set! guimb-header #t))
972 ((help) 970 ((help)
973 (sieve-usage)))))) 971 (sieve-usage))
972 ('()
973 (set! sieve-script-args (cdr x)))))))
974 (getopt-long (command-line) grammar)) 974 (getopt-long (command-line) grammar))
975 975
976 (if (not filename) 976 (cond
977 (begin 977 ((not filename)
978 (display program-name) 978 (display program-name)
979 (display ": missing input filename") 979 (display ": missing input filename")
980 (newline) 980 (newline)
981 (sieve-usage))) 981 (sieve-usage))
982 982 ((not (file-exists? filename))
983 (define guimb? (catch #t
984 (lambda ()
985 (let ((package mu-package))
986 package))
987 (lambda args #f)))
988
989 (if (and guimb? (string? user-name))
990 (set! filename (sieve-expand-filename filename)))
991
992 (if (not (file-exists? filename))
993 (begin
994 (display (string-append 983 (display (string-append
995 program-name 984 program-name
996 ": Input file " filename " does not exist.")) 985 ": Input file " filename " does not exist."))
...@@ -1019,23 +1008,20 @@ ...@@ -1019,23 +1008,20 @@
1019 (newline) 1008 (newline)
1020 (exit 1)) 1009 (exit 1))
1021 (output 1010 (output
1022 (sieve-save-program output)) 1011 (sieve-save-program output guimb-header))
1023 ((not guimb?)
1024 (display program-name)
1025 (display ": Either use guimb to compile and execute the script")
1026 (newline)
1027 (display "or use --output option to save the Scheme program.")
1028 (newline)
1029 (exit 1))
1030 (else 1012 (else
1031 (let ((temp-file (tmpnam)) 1013 (let ((temp-file (tmpnam))
1032 (saved-umask (umask #o077))) 1014 (saved-umask (umask #o077)))
1033 (sieve-save-program temp-file) 1015 (sieve-save-program temp-file)
1034 (load temp-file) 1016 (catch #t
1017 (lambda ()
1018 (load temp-file))
1019 (lambda (key . args)
1020 (apply display-error the-last-stack (current-error-port) args)))
1035 (delete-file temp-file) 1021 (delete-file temp-file)
1036 (umask saved-umask)))) 1022 (umask saved-umask))))
1037 1023
1038 1024 ;;;; End of sieve.scm
1039 1025
1040 1026
1041 1027
......