allow custom option types for (chibi app)

This commit is contained in:
Alex Shinn 2022-07-09 14:59:34 +09:00
parent d03202407b
commit bc18b0cc30

View file

@ -18,6 +18,7 @@
;;> \item{\scheme{(@ <opt-spec>)} - option spec, described below} ;;> \item{\scheme{(@ <opt-spec>)} - option spec, described below}
;;> \item{\scheme{(begin: <begin-proc>)} - procedure to run before main} ;;> \item{\scheme{(begin: <begin-proc>)} - procedure to run before main}
;;> \item{\scheme{(end: <end-proc>)} - procedure to run after main} ;;> \item{\scheme{(end: <end-proc>)} - procedure to run after main}
;;> \item{\scheme{(types: (<type-name> <parser>) ...)} - additional types that can be used in argument parsing}
;;> \item{\scheme{(<proc> args ...)} - main procedure (args only for documentation)} ;;> \item{\scheme{(<proc> args ...)} - main procedure (args only for documentation)}
;;> \item{\scheme{<app-spec>} - a subcommand described by the nested spec} ;;> \item{\scheme{<app-spec>} - a subcommand described by the nested spec}
;;> \item{\scheme{(or <app-spec> ...)} - an alternate list of subcommands} ;;> \item{\scheme{(or <app-spec> ...)} - an alternate list of subcommands}
@ -125,7 +126,7 @@
(let ((args (or (and (pair? o) (car o)) (command-line))) (let ((args (or (and (pair? o) (car o)) (command-line)))
(config (and (pair? o) (pair? (cdr o)) (cadr o)))) (config (and (pair? o) (pair? (cdr o)) (cadr o))))
(cond (cond
((parse-app '() (cdr spec) '() (cdr args) config #f #f) ((parse-app '() (cdr spec) '() (cdr args) config #f #f '())
=> (lambda (v) => (lambda (v)
(let ((proc (vector-ref v 0)) (let ((proc (vector-ref v 0))
(cfg (vector-ref v 1)) (cfg (vector-ref v 1))
@ -150,7 +151,7 @@
;;> \var{fail} with a single string argument describing the error, ;;> \var{fail} with a single string argument describing the error,
;;> returning that result. ;;> returning that result.
(define (parse-option prefix conf-spec args fail) (define (parse-option prefix conf-spec args types fail)
(define (parse-value type str) (define (parse-value type str)
(cond (cond
((not (string? str)) ((not (string? str))
@ -187,7 +188,10 @@
res)) res))
#f)) #f))
(else (else
(list str #f)))))) (cond
((assq type types)
=> (lambda (cell) (list ((cadr cell) str) #f)))
(else (list str #f))))))))
(define (lookup-conf-spec conf-spec syms strs) (define (lookup-conf-spec conf-spec syms strs)
(let ((sym (car syms)) (let ((sym (car syms))
(str (car strs))) (str (car strs)))
@ -302,7 +306,7 @@
;;> is the list of remaining non-option arguments. Calls fail on ;;> is the list of remaining non-option arguments. Calls fail on
;;> error and tries to continue processing from the result. ;;> error and tries to continue processing from the result.
(define (parse-options prefix conf-spec orig-args fail) (define (parse-options prefix conf-spec orig-args types fail)
(let lp ((args orig-args) (let lp ((args orig-args)
(opts (make-conf '() #f (cons 'options orig-args) #f))) (opts (make-conf '() #f (cons 'options orig-args) #f)))
(cond (cond
@ -312,7 +316,7 @@
(not (eqv? #\- (string-ref (car args) 0)))) (not (eqv? #\- (string-ref (car args) 0))))
(cons opts (if (equal? (car args) "--") (cdr args) args))) (cons opts (if (equal? (car args) "--") (cdr args) args)))
(else (else
(let ((val+args (parse-option prefix conf-spec args fail))) (let ((val+args (parse-option prefix conf-spec args types fail)))
(lp (cdr val+args) (lp (cdr val+args)
(conf-set opts (caar val+args) (cdar val+args)))))))) (conf-set opts (caar val+args) (cdar val+args))))))))
@ -332,7 +336,7 @@
;;> all prefixed by \var{prefix}. The original \var{spec} is used for ;;> all prefixed by \var{prefix}. The original \var{spec} is used for
;;> \scheme{app-help}. ;;> \scheme{app-help}.
(define (parse-app prefix spec opt-spec args config init end . o) (define (parse-app prefix spec opt-spec args config init end types . o)
(define (next-prefix prefix name) (define (next-prefix prefix name)
(append (if (null? prefix) '(command) prefix) (list name))) (append (if (null? prefix) '(command) prefix) (list name)))
(define (prev-prefix prefix) (define (prev-prefix prefix)
@ -367,7 +371,7 @@
((null? spec) ((null? spec)
(error "no procedure in application spec")) (error "no procedure in application spec"))
((or (null? (car spec)) (equal? '(@) (car spec))) ((or (null? (car spec)) (equal? '(@) (car spec)))
(parse-app prefix (cdr spec) opt-spec args config init end fail)) (parse-app prefix (cdr spec) opt-spec args config init end types fail))
((pair? (car spec)) ((pair? (car spec))
(case (caar spec) (case (caar spec)
((@) ((@)
@ -383,38 +387,41 @@
(car tail)))) (car tail))))
(new-fail (new-fail
(lambda (new-prefix new-spec new-opt new-args reason) (lambda (new-prefix new-spec new-opt new-args reason)
(parse-option (prev-prefix prefix) opt-spec new-args fail))) (parse-option (prev-prefix prefix) opt-spec new-args types fail)))
(cfg+args (parse-options prefix new-opt-spec args new-fail)) (cfg+args (parse-options prefix new-opt-spec args types new-fail))
(config (conf-append (car cfg+args) config)) (config (conf-append (car cfg+args) config))
(args (cdr cfg+args))) (args (cdr cfg+args)))
(parse-app prefix (cdr spec) new-opt-spec args config (parse-app prefix (cdr spec) new-opt-spec args config
init end new-fail))) init end types new-fail)))
((or) ((or)
(any (lambda (x) (parse-app prefix x opt-spec args config init end)) (any (lambda (x) (parse-app prefix x opt-spec args config init end types))
(cdar spec))) (cdar spec)))
((begin:) ((begin:)
(parse-app prefix (cdr spec) opt-spec args config (parse-app prefix (cdr spec) opt-spec args config
(cadr (car spec)) end fail)) (cadr (car spec)) end types fail))
((end:) ((end:)
(parse-app prefix (cdr spec) opt-spec args config (parse-app prefix (cdr spec) opt-spec args config
init (cadr (car spec)) fail)) init (cadr (car spec)) types fail))
((types:)
(parse-app prefix (cdr spec) opt-spec args config
init end (cdr (car spec)) fail))
(else (else
(if (procedure? (caar spec)) (if (procedure? (caar spec))
(vector (caar spec) config args init end) ; TODO: verify (vector (caar spec) config args init end) ; TODO: verify
(parse-app prefix (car spec) opt-spec args config (parse-app prefix (car spec) opt-spec args config
init end fail))))) init end types fail)))))
((symbol? (car spec)) ((symbol? (car spec))
(and (pair? args) (and (pair? args)
(eq? (car spec) (string->symbol (car args))) (eq? (car spec) (string->symbol (car args)))
(let ((prefix (next-prefix prefix (car spec)))) (let ((prefix (next-prefix prefix (car spec))))
(parse-app prefix (cdr spec) opt-spec (cdr args) config (parse-app prefix (cdr spec) opt-spec (cdr args) config
init end fail)))) init end types fail))))
((procedure? (car spec)) ((procedure? (car spec))
(vector (car spec) config args init end)) (vector (car spec) config args init end))
(else (else
(if (not (string? (car spec))) (if (not (string? (car spec)))
(error "unknown application spec" (car spec))) (error "unknown application spec" (car spec)))
(parse-app prefix (cdr spec) opt-spec args config init end fail))))) (parse-app prefix (cdr spec) opt-spec args config init end types fail)))))
(define (print-command-help command out) (define (print-command-help command out)
(cond (cond