前へ 目次 次へ
参照: cabal-install 関連のリンク 前回までの記事で Main.hs の main 関数の定義に出てくる commandsRun globalCommand commands args の globalCommand と commands の概要を調べた。大まかに言うと globalCommand は cabal コマンドのオプションに関する情報を納めていて、commands は cabal install .. の install のような cabal のコマンドの情報を納めている。もちろん args は cabal -V や caball install の -V や install などのコマンドライン引数のリストだ。これは Main.hs のなかの getArgs アクションによって取得される。 1. commandsRun commandsRun 関数は Distribution.Simple.Commnad 標準モジュールに定義されており、その型は次のようになっている。 commandsRun :: CommandUI a -> [Command action] -> [String] -> CommandParse (a, CommandParse action) 第1引数の CommandUI a 型のデータにはコマンドの情報と、コマンドのオプションの情報が納められている。また [Command action] 型のデータはそのコマンドのサブ・コマンドの情報が納められている。[String] はコマンドライン引数のリストだ。戻り値の CommandParse (a, CommandParse action) 型はコマンドライン引数をパースした結果の構文木だ。再帰的なデータ構造になっている。 commandsRun はこのように、cabal のコマンドライン引数のパーサだ。汎用性があるので、Distribution.Simple.Command モジュールをインポートすれば、cabal 以外にも自作のコマンドのパーサとして利用する事ができるだろう。 commandsRun のコードの冒頭部分は次のようになっている。 commandsRun :: CommandUI a -> [Command action] -> [String] -> CommandParse (a, CommandParse action) commandsRun globalCommand commands args = case commandParseArgs globalCommand' True args of どうやら、commandParseArgs 関数がわからないと解読できないようだ。 2. commandParseArgs commandParseArgs 関数も Distribution.Simple.Command モジュールで定義されており、その冒頭部分は次のようになる。 commandParseArgs command global args = let options = addCommonFlags ParseArgs $ commandGetOpts ParseArgs command order | global = GetOpt.RequireOrder | otherwise = GetOpt.Permute in case GetOpt.getOpt' order options args of 3. GetOpt.getOpt GetOpt.getOpt' という関数が出てくるがこれは一体何なのだろうか。getOpt' 関数は System.Console.GetOpt 標準モジュールで定義されている。これは System.Environment モジュールの getArgs アクションでリストとして取り込んだコマンドライン引数のリストをパースしてオプションの情報を取り出す関数だ。 ところで、getArgsアクションの動作を確認しておいたほうがそのあとのコード解読がやりやすそうだったので ghci で試してみた。 Prelude> import System.Environment Prelude System.Environment> let main = getArgs Prelude System.Environment> :main hello world ["hello","world"] Prelude System.Environment> :main -c --version ["-c","--version"] getArgs では、コマンドラインオプションの先頭のハイフンもそのままとりこまれるのが分かる。 4. getOpt のプログラム例 System.Console.GetOpt モジュールの仕様は結構複雑なので、説明を読んでもよくわからない。そこで、モジュールの文書にあったプログラム例を実行してみた。 module Opts1 where import System.Console.GetOpt import Data.Maybe ( fromMaybe ) data Flag = Verbose | Version | Input String | Output String | LibDir String deriving Show options :: [OptDescr Flag] options = [ Option ['v'] ["verbose"] (NoArg Verbose) "chatty output on stderr" , Option ['V','?'] ["version"] (NoArg Version) "show version number" , Option ['o'] ["output"] (OptArg outp "FILE") "output FILE" , Option ['c'] [] (OptArg inp "FILE") "input FILE" , Option ['L'] ["libdir"] (ReqArg LibDir "DIR") "library directory" ] inp,outp :: Maybe String -> Flag outp = Output . fromMaybe "stdout" inp = Input . fromMaybe "stdin" compilerOpts :: [String] -> IO ([Flag], [String]) compilerOpts argv = case getOpt Permute options argv of (o,n,[] ) -> return (o,n) (_,_,errs) -> ioError (userError (concat errs ++ usageInfo header options)) where header = "Usage: ic [OPTION...] files..." モジュール名が Opts1 なので Opts1.hs というファイルに作成する。ghci で試すと次のようになった。 Prelude> :l Opts1.hs [1 of 1] Compiling Opts1 ( Opts1.hs, interpreted ) Ok, modules loaded: Opts1. *Opts1> :browse Opts1 data Flag = Verbose | Version | Input String | Output String | LibDir String options :: [OptDescr Flag] outp :: Maybe String -> Flag inp :: Maybe String -> Flag compilerOpts :: [String] -> IO ([Flag], [String]) *Opts1> compilerOpts ["-v"] ([Verbose],[]) *Opts1> compilerOpts ["--libdir", "/var/lib/"] ([LibDir "/var/lib/"],[]) *Opts1> compilerOpts ["not_option"] ([],["not_option"]) このプログラム例ではコマンドラインオプションは種類分けされて Flag 型に収められている。オプションがパラメータを取る場合は、Flag 型のコンストラクタのコンテナに入る。 complierOpts 関数(アクション)は String のリストを引数に取り、オプションをスキャンして、オプションは [Flag] リストにして、またオプション以外のコマンド・ライン引数の文字列は [String] リストにして、それらのリストのペアを IO 型にラッピングして返す。 プログラム例の中で getOpt 関数は、compilerOpts 関数の中で、 case getOpt Permute options argv of のように使われている。 5. getOpt 関数 getOpt 関数の型は次のようになる。 getOpt :: ArgOrder a -> [OptDescr a] -> [String] -> ([a], [String], [String]) 第1引数の ArgOrder a の意味がわからないが、System.Console.GetOpt は記事を改めて探索するのでとりあえず置いておいて、第2引数の [OptDescr a] がオプションのリストで、[String] はコマンド・ライン引数のリストだ。戻値は ([a], [String], [String]) となっているが compilerOpts の動作から見ると [a] がオプションのフラグのリストで、[String] が非オプションの文字列のリストだろう。コンテナの最後の [String] の意味が分からないが、case 文でコマンド・ライン引数に文法エラーがあった場合に利用されている。 結局、getOpt を利用する上での中心は [OptDecr a] のリストでオプションのルールをどのように与えるかということになる。プログラム例のオプションのルールである options の定義を再掲する。 options :: [OptDescr Flag] options = [ Option ['v'] ["verbose"] (NoArg Verbose) "chatty output on stderr" , Option ['V','?'] ["version"] (NoArg Version) "show version number" , Option ['o'] ["output"] (OptArg outp "FILE") "output FILE" , Option ['c'] [] (OptArg inp "FILE") "input FILE" , Option ['L'] ["libdir"] (ReqArg LibDir "DIR") "library directory" ] options リストの要素である Option 型はパラメータとして4つのフィールドを持っている。1番目は short option のリスト、第2のパラメータは long option のリスト、3番めはオプションのフラグ (Flag 型)、4番目はオプションの説明文だ。 たとえば options リストの最初のフィールドの値は ['v']、2番めのフィールドは ["verbous"]、3番めのフィールドは (NoArg Verbose) フラグ、4番目のフィールドは "chatty output on stderr" だ。 これらのパラメータは cabal-install の globalCommnad の commandOptions フィールドのデータとも関連しているのだろう。というより、commandOptions フィールドのデータを使って OptDescr flag 型のデータを作成するのだろう。 cabal-install の主要な動作のひとつにコマンド・ライン・オプションの構文解析があるはずだが、GetOpt を利用しているようだ。System.Console.GetOpt は caball-install のコードの中で重要な働きをしているようなので、記事を変えて探索してみる。
by tnomura9
| 2013-12-15 08:01
| Haskell
|
Comments(0)
|
カテゴリ
新型コロナウイルス 主インデックス Haskell 記事リスト 圏論記事リスト 考えるということのリスト 考えるということ ラッセルのパラドックス Haskell Prelude Ocaml ボーカロイド 圏論 jQuery デモ HTML Python ツールボックス XAMPP Ruby ubuntu WordPress 脳の話 話のネタ リンク 幸福論 キリスト教 心の話 メモ 電子カルテ Dojo JavaScript C# NetWalker ed と sed HTML Raspberry Pi C 言語 命題論理 以前の記事
最新のトラックバック
最新のコメント
ファン
記事ランキング
ブログジャンル
画像一覧
|
ファン申請 |
||