Gauche:マニュアルにアクセス
yamasushi(2013/04/11 06:38:36 UTC)interactive/info.scmをもとに、マニュアルを検索するライブラリをつくってみました。述語を指定して、マッチするキーをひいて、取得したマニュアルデータの見出し部分をさらにフィルタします。
($マクロを多用したので、schemeのコードのように見えないかもしれません。(汗)
- yamasushi(2013/04/14 09:34:38 UTC)メモ化部を改善しました。(→Gauche:メモ化)
- yamasushi(2013/04/15 13:33:03 UTC)汎用的に使える部分を切り離してGauche:infoファイルにアクセスに移しました。
- yamasushi(2013/04/16 10:37:19 UTC)メモ化を使うのをやめ、instance-poolを使うようにしました。(→Gauche:infoファイルにアクセス)
- yamasushi(2013/04/18 11:16:32 UTC)モジュールのソースへのアクセスをinfoアクセスのように行うように抽象化しました。
- yamasushi(2013/04/23 22:15:27 UTC) Gauche:モジュールの列挙の成果と組み合わせる。
- 参考にしたblog
Gaucheのinfo関数の表示を日本語にするには - 再帰の反復
http://d.hatena.ne.jp/lemniscus/20100326/1269613137
;;; gaucheのinfoにアクセスする。 ;;; interactive/info.scmを改造した。 ;;; もとになったblog ;;; Gaucheのinfo関数の表示を日本語にするには - 再帰の反復 ;;; http://d.hatena.ne.jp/lemniscus/20100326/1269613137 ;;; interactive/info.scm - online helper ;;; ;;; Copyright (c) 2000-2012 Shiro Kawai <shiro@acm.org> ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; 1. Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; 2. Redistributions in binary form must reproduce the above copyright ;;; notice, this list of conditions and the following disclaimer in the ;;; documentation and/or other materials provided with the distribution. ;;; ;;; 3. Neither the name of the authors nor the names of its contributors ;;; may be used to endorse or promote products derived from this ;;; software without specific prior written permission. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ;;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ;;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ;;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ;;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ;;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ;;; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ;;; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ;;; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; ; TODO コード構成の整理。 ; TODO シンプルなヘルプ ; TODO key ---> 見出し map ; TODO caddrの展開 ; TODO <dictionary> <ordered-dictionary>などの重要だがdocumentに索引のないものに対応 ; TODO 実際のクラス・モジュール情報を見て処理する (define-module textj.gauche-info (extend textj.info-lib textj.info-root) (use gauche.config) (use srfi-1) (use srfi-13) (use gauche.mop.singleton) (use text.tree) (use gauche.generator) (use gauche.dictionary) (use gauche.sequence) (use gauche.lazy) (use util.match) (use text.info) (use gauche-modules) (use pretty-print) ; debug (use komono-dict) (use komono-combinator) (use komono-regexp) (export gauche-info-root <gauche-info-root> <info-index-node> gauche-source <gauche-source> gauche-module-finder <gauche-module-finder> <%node> ;; info-string-generator info-string-lseq info-deftp&body-generator info-deftp&body-lseq info-deftp-generator info-deftp-lseq info-node-function-jp info-node-function-en info-node-variable-jp info-node-variable-en info-node-class-jp info-node-class-en info-node-module-jp info-node-module-en process-deftp-string-list ) ) (select-module textj.gauche-info) (define *source* "*source*") ; ソースファイルを見る。 (define *index-node-source-module-jp* "*module*") (define *index-node-source-function-jp* "*function*") (define *index-node-source-variable-jp* "*variable*") (define *index-node-source-class-jp* "*class*") (define *index-node-source-macro-jp* "*macro*") (define *info-file-jp* "gauche-refj.info") ; 日本語infoを見る (define *info-file-en* "gauche-refe.info") ; 英語infoを見る (define *info-file-dev-en* "gauche-deve.info") ; 開発者manual (define *info-file-gl-en* "gauche-gl-refe") ; Gauche gl (define *index-node-function-jp* "Index - 手続きと構文索引") (define *index-node-variable-jp* "Index - 変数索引") (define *index-node-class-jp* "Index - クラス索引") (define *index-node-module-jp* "Index - モジュール索引") (define *index-node-function-en* "Function and Syntax Index") (define *index-node-variable-en* "Variable Index") (define *index-node-class-en* "Class Index") (define *index-node-module-en* "Module Index") (define *index-node-dev-function-en* "Function and Macro Index") (define *index-node-dev-type-en* "Type Index") (define *index-node-dev-variable-en* "Variable Index") (define *index-node-gl-function-en* "Function and Syntax Index") (define *index-node-gl-variable-en* "Variable Index") (define *index-node-gl-class-en* "Class Index") (define *index-node-gl-module-en* "Module Index") (define *toc-lib-gauche-jp* "ライブラリモジュール - Gauche拡張モジュール") (define *toc-lib-srfi-jp* "ライブラリモジュール - SRFI") (define *toc-lib-utilities-jp* "ライブラリモジュール - ユーティリティ") (define *toc-lib-gauche-en* "Library modules - Gauche extensions") (define *toc-lib-srfi-en* "Library modules - SRFIs") (define *toc-lib-utilities-en* "Library modules - Utilities") ;-------------------------------------- ; type --> node のテーブル ; menu keyword ---> key変換器(関数・文法用) (define gauche-menu-key-converter-fn (rxmatch-lambda ; (setter *)の処理 (重複している場合も含める) [#/^\s*\(setter\s+(\S+)\s*\).*$/ (_ k) k ] ; refなどの重複するエントリの処理 [#/^\s*(\S+)\s*<[^>]+>.*$/ (_ k) k ] ; その他 [else => identity ] )) ; menu keyword ---> key変換器(class用) ;<>記号をつけないクラス ;もあるかもしれないが、そのときはそのときに適宜対応する。$ (define gauche-menu-key-converter-cls (rxmatch-lambda ; ; 通常のエントリの処理 [#/^\s*(\S+)\s*$/ (_ k) (format #f "<~a>" k) ] ; refなどの重複するエントリの処理 [#/^\s*(\S+)\s*<[^>]+>.*$/ (_ k) (format #f "<~a>" k) ] ; ; その他 [else => identity ] )) ; menu keyword ---> key変換器(その他) (define gauche-menu-key-converter (rxmatch-lambda ; refなどの重複するエントリの処理 [#/^\s*(\S+)\s*<[^>]+>.*$/ (_ k) k ] ; その他 [else => identity ] )) (define *info-node-names-source* (alist->hash-table `((function ,*index-node-source-function-jp* ,identity) (variable ,*index-node-source-variable-jp* ,identity) (class ,*index-node-source-class-jp* ,identity) (module ,*index-node-source-module-jp* ,identity) ) ) ) (define *info-node-names-jp* (alist->hash-table `((function ,*index-node-function-jp* ,gauche-menu-key-converter-fn ) (variable ,*index-node-variable-jp* ,gauche-menu-key-converter ) (class ,*index-node-class-jp* ,gauche-menu-key-converter-cls ) (module ,*index-node-module-jp* ,gauche-menu-key-converter ) ) ) ) (define *info-node-names-en* (alist->hash-table `((function ,*index-node-function-en* ,gauche-menu-key-converter-fn ) (variable ,*index-node-variable-en* ,gauche-menu-key-converter ) (class ,*index-node-class-en* ,gauche-menu-key-converter-cls ) (module ,*index-node-module-en* ,gauche-menu-key-converter ) ) ) ) (define *info-node-names-dev-en* (alist->hash-table `((function ,*index-node-dev-function-en* ,gauche-menu-key-converter ) (type ,*index-node-dev-type-en* ,gauche-menu-key-converter ) (variable ,*index-node-dev-variable-en* ,gauche-menu-key-converter ) ) ) ) (define *info-node-names-gl-en* (alist->hash-table `((function ,*index-node-gl-function-en* ,gauche-menu-key-converter-fn ) (variable ,*index-node-gl-variable-en* ,gauche-menu-key-converter ) (class ,*index-node-gl-class-en* ,gauche-menu-key-converter-cls ) (module ,*index-node-gl-module-en* ,gauche-menu-key-converter ) ) ) ) ;-------------------------------------- (define *info-src* (alist->hash-table `((default . refj) ; alias (dev . deve) ; alias (gl . gle) ; alias ;; (ref refj refe) (src ,*source* ,*info-node-names-source* ) (refj ,*info-file-jp* ,*info-node-names-jp* ) (refe ,*info-file-en* ,*info-node-names-en* ) (deve ,*info-file-dev-en* ,*info-node-names-dev-en*) ;; (gle ,*info-file-gl-en* ,*info-node-names-gl-en*) ) ) ) ;-------------------------------------------------------- ; <info-node>のように見せるもの (define-class <%node> [] [(name :init-keyword :name :init-value "") (content :init-keyword :content :init-value "") ;; (file :allocation :virtual :slot-ref (^[self] gauche-source ) ) ;; (next :init-keyword :next :init-value #f) (prev :init-keyword :prev :init-value #f) (up :init-keyowrd :up :init-value #f) ] ) ;-------------------------------------------------------- ; info-index-node的な挙動をするmoduleファインダ (define-class <gauche-module-finder> (<dictionary> <singleton-mixin>) [ (node :init-value (make <%node> :name "*module*" ) ) (*index* :init-value (lazy-dict (make-hash-table 'string=?) (^t (dict-for-each (force *lazy-modules-table*) (^[k v] (dict-put! t k `(,v) ) ) ) ) ) ) (index :allocation :virtual :slot-ref (^[self] ($ force $ ~ self '*index*) ) ) ] ) (define-method initialize ((self <gauche-module-finder>) initargs) (next-method) ) (define gauche-module-finder (instance-of <gauche-module-finder> ) ) ; initializeの定義後に書くこと ; dictionary protocol (define-method dict-get ((d <gauche-module-finder>) key :optional default) (dict-get (~ d 'index) key default ) ) (define-method dict-put! ((d <gauche-module-finder>) key value) (dict-put! (~ d 'index) key value) ) (define-method dict-exists? ((d <gauche-module-finder>) key) (dict-exists? (~ d 'index) key ) ) (define-method dict-delete! ((d <gauche-module-finder>) key) (dict-delete! (~ d 'index) key ) ) (define-method dict-fold ((d <gauche-module-finder>) proc seed) (dict-fold (~ d 'index) proc seed)) (define-method call-with-iterator ((d <gauche-module-finder>) proc . keys) (apply call-with-iterator (~ d 'index) proc keys) ) ; key ---> node-name (define-method ref ((obj <gauche-module-finder>) (key <string>)) (~ obj 'index key) ) ;-------------------------------------------------------- ; <cached-info-file>的な挙動をするソースブラウザ (define-class <gauche-source> (<singleton-mixin>) [ (name :init-value *source* ) (file :init-value #f ) (key-converter-table :init-value #f ) ;; (module :init-value gauche-module-finder ) (function :init-value #f ) (class :init-value #f ) (macro :init-value #f ) (variable :init-value #f ) ] ) (define-method initialize ((self <gauche-source>) initargs) ;#?= "initialize ((self <gauche-source>)" (next-method) ) (define gauche-source (instance-of <gauche-source> ) ) ; initializeの定義後に書くこと ; refを定義する ; ソースの冒頭を取得する (define (head-of-source path) (call-with-input-file path ($ (cut string-join <> "\n" 'suffix ) $ generator->list $ gtake-while #/^\S/ $ port->line-generator $) ) ) ; node-name ---> node or #f (define-method ref ((obj <gauche-source>) (key <string>)) (rxmatch-case key ; 各種ファインダ [ #/\*(\S+)\*/ (_ slot-name) ($ ~ obj $ string->symbol slot-name) ] ; ファインダで求めた。ここにはpath名がくる [ else => (^ (path) (make <%node> :name path :content (string-append path "\n" (head-of-source path) ) ) ) ] ) ) ;-------------------------------------------------------- ; <gauche-info-root> ; gaucheのinfoアクセスの元締め (define-class <gauche-info-root> (<info-root> <singleton-mixin> ) () ) (define-method initialize ((root <gauche-info-root>) initargs) (next-method) ) (define gauche-info-root (instance-of <gauche-info-root> *info-src* ) ) (define-method get-info-paths ((root <gauche-info-root>)) ;#?=root (let* ((syspath (next-method)) (instpath (list (gauche-config "--infodir"))) (in-place (list "../doc"))) ;#?=syspath ;#?=instpath ;#?=in-place (append syspath instpath in-place))) ; info-file-name ----> info ; ※ 一般の場合、key-converterテーブル参照は失敗するかもしれない (define-method ref ((root <gauche-info-root>) (key <string>)) ;#?= "ref ((root <gauche-info-root>) " (rxmatch-case key [ #/^\*source\*$/ ( _ ) gauche-source ] [ else (next-method) ] ) ) ;-------------------------------------------------------- ; deftp文字列の処理。適切なデータがないなら#f ; [ カテゴリ 名前 記述 元の文字列]を返す。 ; predで名前判定する ; (<string> -> x) <string> ---> [<string> <string> <string> <string>] (define (process-deftp-string pred s) (rxmatch-case s ; ( setter * )の処理 [#/^\s+--\s([^:]+):\s*\(setter\s*(\S+)\s*\)\s*(.*)$/ ( org cat name disc) (if (pred name) `( ,cat ,name ,(rxmatch-case disc [#/^\s*$/ (_) #f ] [else => (cut string-append "!setter! " <> ) ] ) ,org ) #f ) ] ; 通常の項目 [#/^\s+--\s([^:]+):\s*(\S+)\s*(.*)$/ ( org cat name disc) (if (pred name) `( ,cat ,name ,(rxmatch-case disc [#/^\s*$/ (_) #f] [else => identity] ) ,org ) #f) ] [else #f] ) ) ; deftp文字列リストの処理。適切なデータがないなら#fを返す ; [ [ カテゴリ 名前 記述 元の文字列] ... ]を返す。 ; predで名前判定する ; (<string> -> x) [<string>] ---> [[<string> <string> <string>] ... ] (define (process-deftp-string-list pred sl) ($ (if-listfn$ (pa$ filter-map (pa$ process-deftp-string pred) ) ) ;$ tee print $ append-map (rxmatch-lambda ; ^cを展開する [#/^(\s+--\sMacro:\s+\^)c(\s+.*)$/ (_ h t) ($ map (cut string-append h <> t) $ cons "_" ; "^_" も追加する $ map ($ string $ integer->char $ + (char->integer #\a) $) $ iota 26)] ; TAGvetorを展開する [#/^(.*)TAG(vector.*)$/ (_ h t) (map (cut string-append h <> t) '("s8" "u8" "s16" "u16" "s32" "u32" "s64" "u64" "f16" "f32" "f64")) ] [else => list ] ) sl) ) ; deftpと説明部を列挙する ; deftp = [ カテゴリ 名前 記述 元の文字列] ; [ 冒頭部(string list) [ [deftp(string-list) 説明(string list)] ... ] , node-name type info-index ] (define-method info-deftp&body-generator ( (root <gauche-info-root>) pred . rest ) ($ gfilter-map (match-lambda [(node-name content . rest ) ($ (pack$ (^(h b) (if b (cons* h b node-name rest) #f )) ($ car $) ($ filter-map (^x (if-let1 v (process-deftp-string-list pred (car x) ) (cons v (cdr x)) #f ) ) $ (cut slices <> 2) $ cdr $) ) $ (cut group-sequence <> :key ($ not $ #/^\s+--\s.*:/ $) ) $ map (cut string-append <> "\n") ; tree->string で変換する用途のために行末に改行をつけておく $ (cut string-split <> #\nl) content ) ]) (apply info-content-generator root pred rest) ) ) (define (info-deftp&body-lseq . arg) ($ generator->lseq $ apply info-deftp&body-generator arg) ) ; deftpの列挙 ; deftp = [ カテゴリ 名前 記述 元の文字列] ; [ deftp(string list) , 説明(string list) , 冒頭部(string list) , node-name , type , info-index ] (define-method info-deftp-generator ( (root <gauche-info-root>) pred . rest ) ($ gconcatenate $ gmap (match-lambda [(head deftp&body . rest ) ($ x->generator $ append-map (match-lambda [(deftp body) (map (cut cons* <> body head rest) deftp)]) deftp&body) ]) (apply info-deftp&body-generator root pred rest) ) ) (define-method info-deftp-lseq ( (root <gauche-info-root>) . arg) ($ generator->lseq $ apply info-deftp-generator root arg) ) ; viewerでみるための文字列generatorを生成する ; 木構造になった、deftp見出しを巡回して、フィルタしながら変換 ; predで名前判定する (define (filter-map-nested-deftp$ pred) (if-listfn$ ($ filter-map (match-lambda ; 冒頭の文字列はそのまま残す [(? string? s) s] ; Node [( ( deftp-list . body ) . child-nodes) (let [[deftp-all ($ (andfn$ (map$ (match-lambda [(_ _ _ org) org])) ) $ process-deftp-string-list (^_ #t) deftp-list)] [deftp-filtered ($ (andfn$ (map$ (match-lambda [(_ _ _ org) org])) ) $ process-deftp-string-list pred deftp-list)] [child-deftp ((filter-map-nested-deftp$ pred) child-nodes)]] ;#?=deftp-all ;#?=deftp-filtered ;#?=child-deftp (cond [ (and (not deftp-filtered) (not child-deftp)) #f] [ (not child-deftp) (append deftp-filtered body ) ] [ (not deftp-filtered) (append deftp-all body child-deftp ) ] [ else (append deftp-filtered body child-deftp) ] ) ) ] ) $ ) ) ) ; p = 見出し前の空白でグループ化した列で ; ( (n deftp ... ) body (m deftp ) .... ) ; これを、レベルを見て木構造にする。 (define (process-nested-deftp p) (cond [(null? p) p] [(string? p) p] [(pair? p) (cond [(string? (car p)) (cons (car p) (process-nested-deftp (cdr p)) ) ] [(pair? (car p)) (receive (body d) (span string? (cdr p)) (let [[n (caar p)] [node (cons (cdar p) body ) ] ] (receive (h t) (span (any-pred string? ($ < n $ car $) ) d) (cons (cons node (process-nested-deftp h)) (process-nested-deftp t) ) ) ) ) ] [else (errorf "??? ~a" (car p)) ] ) ] [else (errorf "??? ~a" p) ] ) ) (define (info-content-string pred content) ($ tree->string $ (filter-map-nested-deftp$ pred) $ process-nested-deftp ;$ tee-exit ;$ pretty-print $ map (match-lambda [ ( ( nn . s ) ... ) (let1 n (car nn) (if n (cons n s) (string-concatenate s) ) ) ]) $ (cut group-sequence <> :key car ) $ map (pack$ cons (rxmatch-lambda [#/^(\s+)--\s.*:/ (_ h) (string-length h)] [else #f]) (cut string-append <> "\n")) $ (cut string-split <> #\nl) content ) ) (define-method info-string-generator ( (root <gauche-info-root>) pred . rest) (gappend ; 関数・文法、変数 (funciton,variable) ($ gmap (match-lambda [( _ x . _ ) (info-content-string pred x ) ]) $ apply info-content-generator root pred :type-filter (any-pred (pa$ eq? 'function) (pa$ eq? 'variable) ) rest ) ; class,module ($ gmap (match-lambda [( _ x . _ ) x] ) $ apply info-content-generator root pred :type-filter (any-pred (pa$ eq? 'class) (pa$ eq? 'module) ) rest ) ; module ( source ) ($ gmap (match-lambda [( _ x . _ ) x] ) $ info-content-generator root pred :type-filter (any-pred (pa$ eq? 'module) ) :tag 'src) ) ) (define-method info-string-lseq ( (root <gauche-info-root>) pred . rest) ($ generator->lseq $ apply info-string-generator root pred rest) ) (define (info-node-function-jp ) (~ gauche-info-root *info-file-jp* *index-node-function-jp*)) (define (info-node-variable-jp ) (~ gauche-info-root *info-file-jp* *index-node-variable-jp*)) (define (info-node-class-jp ) (~ gauche-info-root *info-file-jp* *index-node-class-jp* )) (define (info-node-module-jp ) (~ gauche-info-root *info-file-jp* *index-node-module-jp* )) (define (info-node-function-en ) (~ gauche-info-root *info-file-en* *index-node-function-en*)) (define (info-node-variable-en ) (~ gauche-info-root *info-file-en* *index-node-variable-en*)) (define (info-node-class-en ) (~ gauche-info-root *info-file-en* *index-node-class-en* )) (define (info-node-module-en ) (~ gauche-info-root *info-file-en* *index-node-module-en* ))
- infoコマンド"infoj"はこんな感じに実装しました。
- yamasushi(2013/04/18 11:16:32 UTC)ソースコードへのアクセスをinfoファイルへのアクセスと統合しました。
;;; info閲覧、日本語対応 ;;; gaucheのinfo.scmを日本語対応にする ;;; Gaucheのinfo関数の表示を日本語にするには - 再帰の反復 ;;; http://d.hatena.ne.jp/lemniscus/20100326/1269613137 ;;; > lib/gauche/interactive/info.scmを変更する。ひとつは、 ;;; > (define *info-file* "gauche-refe.info") ;;; > を ;;; > (define *info-file* "gauche-refj.info") ;;; > に変える。 ;;; > もうひとつは、info関数の定義に出てくる文字列リテラル ;;; > 「"Function and Syntax Index"」を「"Index - 手続きと構文索引"」に変えて、 ;;; > さらに適切にエンコードを指定する。 ;;; ;;; interactive/info.scm - online helper ;;; ;;; Copyright (c) 2000-2012 Shiro Kawai <shiro@acm.org> ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; 1. Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; 2. Redistributions in binary form must reproduce the above copyright ;;; notice, this list of conditions and the following disclaimer in the ;;; documentation and/or other materials provided with the distribution. ;;; ;;; 3. Neither the name of the authors nor the names of its contributors ;;; may be used to endorse or promote products derived from this ;;; software without specific prior written permission. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ;;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ;;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ;;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ;;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ;;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ;;; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ;;; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ;;; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; (define-module textj.view-infoj (use gauche.dictionary) ; (use textj.gauche-info) (use komono-combinator) (export ofni infoj infoe modulegrep infogrep infogrepe ) ) (select-module textj.view-infoj) ;(format (standard-error-port) "view-infoj loaded\n") (define viewer (viewer gauche-info-root)) (define-method infogrep ( (rx <regexp>) :optional (info-file-tag 'default) ) ;#?=rx ($ (andfn$ viewer) $ (^x (if (pair? x) (string-join x "\n") #f ) ) (info-string-lseq gauche-info-root rx :tag info-file-tag ) ) ) (define-method infogrep ( (fn <string>) :optional (info-file-tag 'default)) ;#?=fn (let* [[fn (regexp-quote fn)] [rx (string->regexp fn :case-fold #t )] ] (infogrep rx info-file-tag) )) (define-method infoj ( (fn <string>) :optional (info-file-tag 'default) ) ;#?=fn (rxmatch-case fn ;[ #/<(\S+)>/ (_ class-name ) (infoj class-name info-file-name ) ] [ #/^(\S+)->$/ (_ from-what) ($ (cut infogrep <> info-file-name) $ string->regexp $ format #f "^~a->\\S+$" $ regexp-quote from-what) ] [ #/^->(\S+)$/ (_ to-what) ($ (cut infogrep <> info-file-name) $ string->regexp $ format #f "^\\S+->~a$" $ regexp-quote to-what) ] [ #/^-if$/ (_) (infogrep #/^\S+-if$/ info-file-name) ] [ #/^if-$/ (_) (infogrep #/^if-\S+$/ info-file-name) ] [ #/^-let1$/ (_) (infogrep #/^\S+let1$/ info-file-name) ] [ #/^-let$/ (_) (infogrep #/^\S+-let\S+$/ info-file-name) ] [ #/^do-$/ (_) (infogrep #/^do\S+$/ info-file-name) ] [ #/^-filter$/ (_) (infogrep #/^\S+-filter[!]?$/ info-file-name) ] [ #/^-map$/ (_) (infogrep #/^\S+-map[!]?$/ info-file-name) ] [ #/^-map-accum$/ (_) (infogrep #/^\S*map-accum$/ info-file-name) ] [ #/^-fold$/ (_) (infogrep #/^\S+-fold$/ info-file-name) ] [ #/^-fold-right$/ (_) (infogrep #/^\S+-fold-right$/ info-file-name) ] [ #/^-unfold$/ (_) (infogrep #/^\S+[-]?unfold.?$/ info-file-name) ] [ #/^string-$/ (_) (infogrep #/^string-\S+$/ info-file-name) ] [ #/^generator-$/ (_) (infogrep #/^generator-\S+$/ info-file-name) ] [ else (let* [[fn ($ format #f "^~a[0$*!]?$" $ regexp-quote fn)] [rx (string->regexp fn :case-fold #t )] ] (infogrep rx info-file-tag) ) ] ) ) (define-method infoj ( (fn <symbol>) . rest) (apply infoj (symbol->string fn) rest)) (define (infoe fn) (infoj fn 'refe)) (define (infogrepe p) (infogrep p 'refe)) ;逆引きする (define *lazy-ofni-hash* (make-lazy-ofni-hash gauche-info-root 'ref) ) (define-method ofni ( (rx <regexp>) ) ($ (andfn$ viewer) $ (if-stringfn$ (cut dict-fold <> (^(k v s) (if (rx k) (string-append "\n" k "\n" (string-join v " , ") "\n" s ) s ) ) "" )) $ force *lazy-ofni-hash*) ;; (values)) (define-method ofni ( (str <string>) ) ($ ofni $ (cut string->regexp <> :case-fold #t ) $ regexp-quote str) )
- テーブルを逆引きするコマンド ofni も作って見ました。
"file"で逆引きするとこうなります。Filesystem utilities file.util Filtering file content file.filter , file-filter-map , file-filter-for-each , file-filter Loading Scheme file load-from-port , load , current-load-port , current-load-path , current-load-next , current-load-history , add-load-path , *load-path* Lock files with-lock-file , lock-file-name Profiler API profiler-stop , profiler-start , profiler-show , profiler-reset Other file operations sys-ttyname , sys-truncate , sys-pipe , sys-mkfifo , sys-isatty , sys-ftruncate , sys-chdir ....
- テーブルを逆引きするコマンド ofni も作って見ました。
- 検索結果の例 たとえばrefを検索するとこうなります。
6.15 ハッシュテーブル ============================= -- Method: ref (ht <hash-table>) key :optional default -- Method: (setter ref) (ht <hash-table>) key value `hash-table-get'と`hash-table-put!'のメソッド版です。 6.18.2 万能アクセサ ------------------------- -- Generic function: ref object key :optional args ... -- Generic function: (setter ref) object key value 多くの集合型はこのジェネリックファンクションを特殊化し、 統一されたアクセス方法と変更方法を提供しています。 `ref'のオプショナル引数ARGSの意味はメソッド毎に異なりますが、 最初のオプショナル引数は、OBJECTのKEYに対する値が無い場合の フォールバック値として使われるのが普通です。 正確な動作の定義は、`ref'メソッドを提供しているクラスごとに説明されています。 `~'の動作は次のコードで理解できるでしょう。 (define ~ (getter-with-setter (case-lambda [(obj selector) (ref obj selector)] [(obj selector . more) (apply ~ (ref obj selector) more)]) (case-lambda [(obj selector val) ((setter ref) obj selector val)] [(obj selector selector2 . rest) (apply (setter ~) (ref obj selector) selector2 rest)]))) (Gaucheは最適化のためにいくつかの型で短絡経路を使うこともあるので、 実際の実装とは異なります) .....
- 検索結果の例 "TAGvector"は展開してから文字列にしますので、make-u8vectorで検索するとこうなります。
9.31.1 ユニフォームベクタの基本操作 ------------------------------------------------- -- Function: make-u8vector LEN :OPTIONAL FILL [SRFI-4] 長さLENのTAGvectorを作成して返します。各要素はFILLで 初期化されます。正確な整数のベクタに対しては、FILLは正確な整数でなければならず、 また有効な範囲内の値でなければなりません。 FILLが省略された場合、各要素の初期値は不定です。 (make-u8vector 4 0) => #u8(0 0 0 0)
- yamasushi(2013/04/13 06:12:52 UTC) 変数pathのように入れ子になっている項目の内側の場合、親も表示するようにしてみました。
- pathを検索するとこのようになります。
9.13 `gauche.logger' - ユーザレベルのロギング ======================================================== -- Class: <log-drain> ログメッセージの行き先を表現するオブジェクトです。 デフォルトのログの行き先として、グローバルな`<log-drain>'のインスタンスが ひとつ作られます。 ログをいくつかにわけて出力する場合などは`make'メソッドを使って いくつでも`<log-drain>'のインスタンスを作ることができます。 -- Instance Variable of <log-drain>: path ログファイルのパス名か、`#t'、`#f'、あるいはシンボル`syslog' の値を取ります。このスロットが`#t'の場合、ログメッセージは現在のエラーポートに 書き出されます。`#f'の場合は`log-format'は ログを書き出すかわりにフォーマットされたログメッセージを文字列として返します。 シンボル`syslog'の場合はメッセージがシステムログへと送られます。 このスロットの初期値は`#f'です。 ...
- pathを検索するとこのようになります。
- コマンドラインからgaucheのヘルプを引きます。
#!/usr/bin/env gosh ; /* -%- lang:scheme indent-width: 2; use-tabs: no; strip: yes -%- (use gauche.parseopt) (use textj.view-infoj) (define (main args) (let-args (cdr args) [[ofni-mode "ofni"] [ofni-mode-rx "ofnix"] [module-mode "m"] [module-mode-rx "mx"] [grep-mode "g"] [grep-mode-rx "gx"] [else [opt . _ ] (print "不明なオプション : " opt) (exit) ] . args] (cond [(null? args) (error "キーワードを指定すること")] [ ofni-mode (ofni (car args))] [ ofni-mode-rx (ofni ($ string->regexp $ car args))] [ module-mode (modulegrep (car args))] [ module-mode-rx (modulegrep ($ string->regexp $ car args))] [ grep-mode (infogrep (car args))] [ grep-mode-rx (infogrep ($ string->regexp $ car args))] [ else (infoj (car args))] ) ) 0 )
(※ gauche-classes、gauche-modulesのコードはGauche:モジュールの列挙にあります。)