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が使われていたので、継続は力也なんでしょうな。