gencomp 確認 (14)

やっぱ手を動かさないと駄目だな、と言いつつ以下なソレをでっち上げ。

(use gauche.parseopt)

(define (main args)
  (let-args (cdr args)
      ((keep-private-macro "keep-private-macro=s" #f)
       (ext-module "ext-module=s" #f)
       (output-base "o|output=s" #f)
       . args)
    (when keep-private-macro
          (format #t "keep-private-macro = ~s\n" keep-private-macro))
    (when ext-module
          (format #t "ext-module = ~s\n" ext-module))
    (when output-base
          (format #t "output-base = ~s\n" output-base))
    (format #t "args = ~s\n" args))
  )

上記はスクリプトにしてナニ。確認事項は以下。

  • オプション引数の正常な取り扱い
    • 一つ指定
    • 二つ指定
      • 定義順
      • 定義順をあえて外す
    • オプション引数と普通の引数
      • 通常の指定
      • 普通の引数の後に指定されたオプション引数は無視
    • オプション文字列間違い
      • 例外発生
    • オプション引数指定なし

ヤッてみます。

$ gosh test2.scm -keep-private-macro=xx
keep-private-macro = "xx"
args = ()
$ gosh test2.scm -keep-private-macro xx
keep-private-macro = "xx"
args = ()
$ gosh test2.scm --keep-private-macro=xx
keep-private-macro = "xx"
args = ()
$ gosh test2.scm --keep-private-macro xx
keep-private-macro = "xx"
args = ()
$

二つ指定で色々。

$ gosh test2.scm -keep-private-macro x -ext-module=y z
keep-private-macro = "x"
ext-module = "y"
args = ("z")
$ gosh test2.scm -ext-module=y -keep-private-macro x z
keep-private-macro = "x"
ext-module = "y"
args = ("z")
$

順不同。ただし

$ gosh test2.scm -keep-private-macro x z -ext-module=y
keep-private-macro = "x"
args = ("z" "-ext-module=y")
$

は仕様上、許容されてない。あと、オプション文字列間違いは

$ gosh test2.scm -keep-private-macr=xx
*** ERROR: unrecognized option: "keep-private-macr"
Stack Trace:
_______________________________________
  0  (build-option-parser (list (list "keep-private-macro=s" (lambda x  ...
        [unknown location]
$

叱られる。オプション無しだと以下なカンジ。

$ gosh test2.scm x yy zzz
args = ("x" "yy" "zzz")
$

let-args 掘ってくのは別途で。

(match args ((scmfile) ...)) の動作について

  • ext/util/util-match-lib.c がソースな模様
  • libsrc/util/match.scm がその元な模様

gencomp では以下な記述 (main 手続きの一部のみ

    (match args
      ((scmfile)
       (when ext-module
         (ext-module-file (ensure-ext-module-file ext-module)))
       (do-it scmfile (or output-base
                          (sys-basename (path-sans-extension scmfile))))
       (when ext-module (close-output-port (ext-module-file))))
      (else (print "Usage: gosh gencomp [--keep-macro] <file.scm>")
            (exit 0)))

最初は scmfile ってパターンは何か特別な記述? とか手続き? とか色々カン違いしながら色々調べてたんですが、どうやら残りが一つじゃないとダメ、という意味しかない模様。
ええと (match args ((scmfile) ...)) の意図は (scmfile . '()) かどうか、という意味らしい。成程。
てーコトはオプション引数以外は引数一つだかんね、という意味ですな。先のナニを以下に修正して試験。

(use util.match)
(use gauche.parseopt)

(define (main args)
  (let-args (cdr args)
      ((keep-private-macro "keep-private-macro=s" #f)
       (ext-module "ext-module=s" #f)
       (output-base "o|output=s" #f)
       . args)
    (when keep-private-macro
          (format #t "keep-private-macro = ~s\n" keep-private-macro))
    (when ext-module
          (format #t "ext-module = ~s\n" ext-module))
    (when output-base
          (format #t "output-base = ~s\n" output-base))
    (match args
	   ((scmfile)
	    (format #t "scmfile = ~s\n" scmfile))
	   (else
	    (print "Usage: gosh gencomp [--keep-macro] <file.scm>")
	    )))
  )

で、試験。

$ gosh test3.scm  x
scmfile = "x"
$ gosh test3.scm 
Usage: gosh gencomp [--keep-macro] <file.scm>
$ gosh test3.scm -o xxx.out yyy
output-base = "xxx.out"
scmfile = "yyy"
$

なんと言えば良いかわかりませんが便利だなぁ。(感想が微妙杉

sys-dirname について

マニュアルによれば (use file.utils) しないとダメな模様

gosh> (use file.util)
#<undef>
gosh> (sys-dirname "/home/hoge")
"/home"
gosh>

上記は ensure-ext-module-file 手続きのナニ

(define (ensure-ext-module-file filename)
  (let1 dir (sys-dirname filename)
    (unless (file-exists? dir)
      (make-directory* dir))
    (open-output-file filename)))

ええと、ディレクトリが無ければ作って出力ファイルとして open して open-output-file の戻りを戻す、のでしょうか。
ちなみに呼び出し元な記述は以下 (main 手続きの一部のみ

    (match args
      ((scmfile)
       (when ext-module
         (ext-module-file (ensure-ext-module-file ext-module)))

ちなみに ext-module-file はグローバルなスコープで定義されてた

(define ext-module-file (make-parameter #f))

これも動作確認。

gosh> (use gauche.parameter)
#<undef>
gosh> (define test (make-parameter #f))
test
gosh> (test "a")
#f
gosh> (test)
"a"
gosh> (test)
"a"
gosh> (test "b")
"a"
gosh> (test)
"b"
gosh> 

これは gauche 本の 22.7 節に解説あり。let-args 色々試してみるのは面白そげ。