apropos
前回の最後にやったgauche用のslimeなんだけど、指示に従ってsrcエリアの情報を参照するように設定すると、不可解なエラーに落ちる。で、そのコードを抜き出してみた。まずは実行結果。
gosh> ,l ./aa.scm
*** READ-ERROR: Read error at "(input string port)":line 1: extra close parenthesis `]'
While loading "./aa.scm" at line 23
Stack Trace:
_______________________________________
0 (proc l)
at "./aa.scm":9
1 (load-operator-args gauche-refe-path)
at "./aa.scm":23
実験に使った、思いっきりの簡略版。
(define (grep regex-str file proc)
(let ((regex (string->regexp regex-str)))
(with-input-from-file file
(lambda ()
(let loop ((acc '()))
(let ((l (read-line)))
(cond ((eof-object? l) (reverse acc))
(else (if (regex l)
(loop (cons (proc l) acc))
(loop acc))))))))))
(define gauche-refe-path "/home/sakae/src/Gauche-0.9.8/doc/gauche-refe.texi")
(define (load-operator-args gauche-refe-path)
(grep "^@defun|^@defmac|^@defspec|^@deffn" gauche-refe-path
(lambda (line)
(read-from-string
(regexp-replace-all* #`"(,line)"
#/@dots{}/ "..."
#/@code{(\S*)}/ "\\1"
#/@def\w+ / ""
#/:optional/ "&optional"
#/\[(.*)\]/ "&optional \\1")))))
(define ZZZ (load-operator-args gauche-refe-path))
docの下に有るinfoの原稿から、冒頭が@defun等で始まる行を抜き出して、その行内を改変。 そして、read-from-stringで、変更済の文字列をリストにしてる。
その為の仕掛けがregex-replase-allに並置されてる所だ。マッチした文字列の前後を括弧に囲ってる。上手い方法だな。最初は理解出来なかったけどね。
grepの本体では、加工されてリストになったものをどんどんとconsしてる。
どうも出来上がった結果に問題がありそうなんだけど、目で確認したい。guardとか言うのを使うと、その瞬間を捉えられるそうなんだけど、オーソドックスな方法を取った。 read-from-stringを外しておいて、文字列をcons。その結果をファイルに落とした。
gosh> (define oo (open-output-file "ZZZ")) oo gosh> (pprint ZZZ :port oo) #<undef> gosh> (close-port oo)
文字列に]は現れないはずなんだけど、検索すると、
(base) [sakae@c8 tmp]$ grep -- ] ZZZ "(dotimes (&optional variable] num-expr [result) body ...)" "(dolist (&optional variable] list-expr [result) body ...)" :
そして原稿の方
(base) [sakae@c8 doc]$ grep dotimes gauche-refe.texi
@defmac dotimes ([variable] num-expr [result]) body @dots{}
正規表現ってのは、難しいな。誰だこんな便利なやつを発明したのは? 際限なく拡張するperlは趣味人の集まりだなあ。ハッカーの巣窟はBugの巣窟になりますよ。
r7rsの怪
前回からの続き。普通のgoshを起動した積りが、途中からr7rsモードに移行しちゃってて、不思議だなあと思ってた。
(defun geiser-gauche--parameters ()
`("-I" ,(expand-file-name "gauche/geiser" geiser-scheme-dir) "-i" "-l" "gosh.scm"))
geiser-gauche.el/geiser-gauche--startupの一節を真似てみる。
(base) [sakae@c8 geiser]$ gosh -I . -l gosh.scm -i
gosh> (begin (import (geiser)) (write `((result ) (output . ""))) (newline))
*** ERROR: proper list required for function application or macro use: (output . "")
While compiling "(standard input)" at line 1: (begin (import (geiser)) (write `((result) (output . ""))) (newline))
Stack Trace:
_______________________________________
0 (eval expr env)
at "/usr/local/share/gauche-0.97/0.9.8/lib/gauche/interactive.scm":269
gosh[r7rs.user]>
不思議発見である。冒頭に(import (xxx))ってのが来ると、goshはr7rs形式で書かれているものと思って、-r7 モードに切り替えてしまう。以後ずっとrsr7モードとして動作するとな。
apropos
geiserのchez側のcodeを見ていると、何やらmoduleって語句が頻出してる。これはきっと補完のデータとか引数の情報を抽出してるに違いない。先回りしてgaucheのやつを調べておくか。関数名ならaproposだな。ソースに当たる。lib/gauche/interactive.scm
;;; Apropos - search bound symbols matching given pattern
;;;
;;; (apropos 'open) print bound symbols that contains "open"
;;; in its name
;;; (apropos #/^(open|close)/) you can use regexp
;;;
;;; (apropos 'open 'scheme) search symbols only in a single module
(define-syntax apropos
(syntax-rules ()
[(_ item) (%apropos item (current-module) #f)]
[(_ item module) (%apropos item module #t)]
))
引数の与え方に2つのパターンが有るとな。そのパターンをマクロで処理してる。下請けは%付きのaproposか。期待してた、結果をリストにするような機能は付いていない。まあ、人間相手のマクロだからしょうがないか。どうしてもリスト化したいなら、改造しろとな。
改造は最後の手段として、結果をファイルに落としておきたい。どうする?
(let ((keep (current-output-port))) (current-output-port (open-output-file "ZZZ")) (apropos #/.*/) (current-output-port keep))
一時的にファイルポートを現在のポートに挿げ替えて、aproposさせる。終了したらポートを元に戻しておく。
(with-output-to-file "KEY" (^() (apropos #/.*/ 'keyword)))
もっと手軽にやるなら、上記の方法でも良い。^ は、lambdaの代わりね。
(base) sakae@debian:tmp$ cut -d'(' -f2 ZZZ | sort | uniq -c | sort -nr
1619 gauche)
290 keyword)
194 scheme)
30 gauche.interactive)
26 null)
4 user)
こうやって取得した結果をモジュール名でヒストグラム化してみた。6種類のモジュールが初期のrepl環境で有効になってるのね。他のモジュールも利用するなら、先にuseしておけばよいな。
repl上で定義したシンボルは、userモジュール内に格納されるんだな。
gosh> (define (dump module-name)
(hash-table-keys (module-table (find-module module-name))))
dump
gosh> (define hoge-fuga 123)
hoge-fuga
gosh> (find-module 'user)
#<module user>
gosh> (module-table (find-module 'user))
#<hash-table eq? 0x7f6909062b40>
gosh> (dump 'user)
(*program-name* import hoge-fuga dump *argv* help)
hashならキーに対してバリューもあるはず。
gosh> (hash-table-values (module-table (find-module 'user))) (#<gloc user#*program-name*> #<gloc user#import> #<gloc user#hoge-fuga> #<gloc user#dump> #<gloc user#*argv*> #<gloc user#help>)
これを使うのは評価器ですとな。
gosh> (apropos 'select-module) select-module (gauche) gosh> (define-in-module scheme select-module select-module) select-module gosh> (apropos 'select-module) select-module (gauche) select-module (scheme)
module間を移動するのに、select-moduleを使う。だが、こやつはgaucheなモジュールにしか入っていない。userモジュールからはgaucheが見えるんでselect-moduleが使える。
だが、間違ってschemeモジュールの中に入ってしまうと、脱出手段が無くなる。そんな事もあろーかと、schemeモジュールの中に、select-moduleを忍ばせておく。
info lookup for gauche
emacsからinfoを引く設定 by shiroさん。
(defun gauche-info-index (topic)
(interactive
(list (read-string
(concat "Gauche help topic : ")
(current-word))))
(switch-to-buffer-other-window (get-buffer-create "*info*"))
(info "/usr/local/share/info/gauche-refe.info.gz")
(Info-index topic))
(define-key global-map "\C-x\C-j" 'gauche-info-index)
rlwrap + gosh
普通のgoshを使い易くする設定。
what is company
geiserにはcompanyって言う補完機能が使われていたので、少し資料収集。
company-mode support through third-party backends
自作言語 (LuneScript) の emacs company-mode backend 設定
車輪の再発明? かな。
Emacs で Language Server Protocol を使ってみる
「Emacsのトラノマキ」連載第09回「auto-completeを使おう」(松山智大)
auto-complete
取り合えずschemeでも補完って事で、auto-completeを入れておく。
;; auto-complete using dict
(require 'auto-complete-config)
(ac-config-default)
(setq ac-use-menu-map t) ;; ctl-n/p
(add-to-list 'ac-dictionary-directories
"~/.emacs.d/elpa/auto-complete-20170125.245/dict")
(set-face-background 'ac-selection-face "blue")
(set-face-foreground 'ac-completion-face "red")
(set-face-background 'ac-completion-face "gray")
dictの中には色々な言語の辞書が格納されている。勿論scheme用も備え付け。だがこの辞書は貧弱なので、rlwrapの奴を利用しよう。単にリンクを張るだけって言うインチキな方法でね。
[sakae@fb dict]$ mv scheme-mode scheme-mode.org [sakae@fb dict]$ ln -s ~/.gosh_completions scheme-mode
そしてgoshの起動用。
;; scheme (setq scheme-program-name "gosh -i") (autoload 'scheme-mode "cmuscheme" "Major mode for Scheme." t) (autoload 'run-scheme "cmuscheme" "Run an inferior Scheme process." t) (defun scheme-other-window () (interactive) (switch-to-buffer-other-window (get-buffer-create "*scheme*")) (run-scheme scheme-program-name)) (define-key global-map "\C-cC-z" 'scheme-other-window)
これで rlwrpa+gosh の環境が、emacs上に実現出来た。emacsで動いているって事はeditor主体で、時々replって事ね。
[sakae@fb /tmp]$ export EDITOR=emacs [sakae@fb /tmp]$ gosh gosh> (ed "aa.scm") Reload "aa.scm"? [y/N]: y
まあ、replから好きなeditorを呼び出せるから、emacsに拘る必要は無いんだけどね。詳細は、,doc edとかすれば出てくる。
etc
https://b.hatena.ne.jp/search/tag?q=gauche
暫くはクリスマスのクッキー代わりに食べていよう。 Advent Calendar 2019 は、来年のお楽しみ!
chezのコードを見ていたら、call/ccが使われていたので、継続は力也なんでしょうな。