2014/12/24


この記事はVim Advent Calendar 2014 - Qiita 24日目の記事です。

Matz さんが streem という、ストリーム指向言語の開発を始めるらしいです。

お兄ちゃん

https://github.com/matz/streem

まだ文法の設計段階ではあるけど、それなのにかなりの量の pull-req がバンバンと来てて凄いなーと思いつつも「この pull-req 量だと僕には出番無いなー」と思ったのと「Matz さんがもしかしたら Go で streem を実装するかもしれない」という記事を読み「streem の他言語実装が一つ消えてしまう。これはまずい。」と思ったので、README.md に書かれているサンプルだけを頼りに streem を Vim script で実装してみました。

SlipStreem!

先日はネタで streem のマネをして golang で実装したりしましたが、本日ネタが無い中にどうしても Vim script で streem を実装したくなったのでやってみました。

どんなものか

とりあえずこんな事が出来ます。まず以下のバッファを用意します。

foo
bar
baz

そして以下のコマンドを実行します。

:%Streem {|x| x += " Matz" } | STDOUT

すると画面に

foo Matz
bar Matz
baz Matz

と表示されます。

どうやって動いているのか

まず、Streem コマンドは Vim の range から行を入力として扱います。つまり上記で言えば ['foo', 'bar', 'baz'] となります。

そして引数のコマンドを解析し、AST(抽象構文木)に分解します。分解に使ったマッチパターンテーブルは以下の通り。

let s:tbl = [
\  ['stmts',
\    [
\      { 'type''node''match': ['stmt', ['lb''stmt']], 'eval''s:stmts' },
\    ],
\  ],
\  ['stmt',
\    [
\      { 'type''node''match': ['expr', ['|''expr']], 'eval''s:stmt' },
\    ],
\  ],
\  ['expr',
\    [
\      { 'type''node''match': ['expr_node''sp''==''sp''expr_node'], 'eval''s:op_eqeq' },
\      { 'type''node''match': ['if''sp''expr''sp''end'], 'eval''s:expr_if' },
\      { 'type''node''match': ['ident''('')'], 'eval''s:op_call' },
\      { 'type''node''match': ['ident''(''expr_node'')'], 'eval''s:op_call' },
\      { 'type''node''match': ['ident''sp''=''sp''expr_node'], 'eval''s:op_let' },
\      { 'type''node''match': ['ident''sp''+=''sp''expr_node'], 'eval''s:op_plus' },
\      { 'type''node''match': ['expr_node', ['sp''|''sp''expr_node']], 'eval''s:expr' },
\      { 'type''node''match': ['expr_node'], 'eval''s:expr' },
\    ],
\  ],
\  ['expr_node',
\    [
\      { 'type''node''match': ['{''sp''|''ident''|''sp''}'], 'eval''s:expr_func' },
\      { 'type''node''match': ['{''sp''|''ident''|''sp''stmts''sp''}'], 'eval''s:expr_func' },
\      { 'type''node''match': ['ident'], 'eval''s:expr' },
\      { 'type''node''match': ['number'], 'eval''s:expr' },
\      { 'type''node''match': ['string'], 'eval''s:expr' },
\    ],
\  ],
\  ['string', [{ 'type''regexp''match''\("[^"]*"\|''[^'']*''\)''eval''s:expr_string' }]],
\  ['number', [{ 'type''regexp''match''[0-9]\+''eval''s:expr_number' }]],
\  ['ident', [{ 'type''regexp''match''[a-zA-Z][a-zA-Z0-9]*''eval''s:expr_ident' }]],
\  ['+=', [{ 'type''string''match''+=''eval''' }]],
\  ['=', [{ 'type''string''match''=''eval''' }]],
\  ['|', [{ 'type''string''match''|''eval''' }]],
\  ['if', [{ 'type''string''match''if''eval''' }]],
\  ['end', [{ 'type''string''match''end''eval''' }]],
\  ['sp', [{ 'type''regexp''match''[ \t]*''eval''' }]],
\  ['lb', [{ 'type''regexp''match''[ \t]*[\\r\n;]\+[ \t]*''eval''' }]],
\  ['{', [{ 'type''string''match''{''eval''' }]],
\  ['}', [{ 'type''string''match''}''eval''' }]],
\]

これを YACC っぽくパースし、各ノードに分解します。例えば += オペレータであれば以下のノードになります。

{'type''op_plus''value': [{'type''ident''value''x'}{'type''expr''value': [{'type''string''value''Matz'}]}]}

これを小さな VM (今回は時間が無くて streeem が実装している程の命令をサポート出来ませんでした)で実行します。STDOUT は入力を echo するだけのオブジェクトです。

また今回は残念ですが concurrency ではありません。メモリを使いシーケンシャルに実行しています。

ただ、これだけは覚えておいて下さい。

Vim に出来ないから実装しなかった訳ではない

やろうと思えば remote API を使い、複数立ち上げた vim と非同期通信を行いながら結果を集める事だって出来ます。

とここまで書きましたが、そろそろクドいし面倒臭くなってきたと思うので、どうやって動いているか知りたい人はソースを見てください。

mattn/streem-vim - GitHub
https://github.com/mattn/streem-vim

さいごに

さて、明日で Vim Advent Calendar 2014 が完走します(2日程抜けてしまいましたが)。皆さんお疲れ様でした。まさか開発されて20年近くにもなるテキストエディタでこれだけのブログ記事があがって来るとは誰が想像したでしょうか。

また今年も数多くの不具合報告が vim-jp へと寄せられ、数多くのバグが vim-jp によって修正されました。バグ報告頂いた皆さん、そしてパッチを書いてくれた vim-jp のメンバに感謝したいと思います。ありがとうございました。

来年もよい Vim 年になる事を祈って、僕の記事を終えさせて頂きます。

皆様、良いお年を。

ソフトウェア デザイン 2015年 01月号 [雑誌] ソフトウェア デザイン 2015年 01月号 [雑誌]

雑誌 / ¥3,399 (1970年01月01日)
 
発送可能時間:

Posted at by



2014/07/11


こんにちわ。Vim scriptサポーターズの mattn です。

ちょうど3年程前、Vimテクニックバイブルという書籍を執筆させて頂きました。

Big Sky :: Vimテクニックバイブル ~作業効率をカイゼンする150の技
http://mattn.kaoriya.net/software/vim/20110810203558.htm

おかげ様で、色んな方から反響を頂き執筆して良かったと思いました。初めて自分が書いた書籍が販売されるという高揚感に包まれる中、書籍の販売からたった数週間後、何を思ったか僕と KoRoN さんは github 上に vim-users-jp というオープングループを作る事になりました。

Big Sky :: github上にvim-users-jpというorganizationを作った。
http://mattn.kaoriya.net/software/vim/20110907120904.htm

そして数日後、vim-jp が誕生します。

vim-jp » Vimのユーザーと開発者を結ぶコミュニティサイト
http://vim-jp.org/

今から思えば、かなり思い切った事をやったもんだなーと我ながら思います。あの思いっきりが無かったら vim-jp は生まれなかったと思います。

あれからVim界隈は人気に陰りが出るどころか、さらなる進展を遂げ、vim-jp から提供するパッチが vim_dev に溢れ、多くの contribute authors を排出し、多くの優秀な Vim プラグインが作られ、毎週 vimrc 読書会が開催され、本当に20年も昔に作られたテキストエディタなのか?と疑いたくなる状況となりました。

Vim script の知名度についてはどうでしょうか?プラグインを書く人が増えたものの、ちゃんとした誘導書が無い為に色んなテクニックが氾濫し、その為に敷居があがり「変態言語」と呼ばれる部類に入れられる事も多い様です。

そして個々の力技により色んなハックが生まれ、時に Vimmer は怖いと言われる事も目にします。しかしそれ程に Vimmer は Vim script を愛しているのです。

ただし良く考えて下さい。

プログラミング言語 Vim script は本来、vimrc を記述する為の言語なのです。

ちゃんとした vimrc を書く為にはちゃんとした Vim script を書く必要があるのです。そして誰かがちゃんとしたハックを何処かに記し、皆が同じハックを共有出来るべきだと思うのです。

Vimテクニックバイブルは Vim の凄さを広める為に生まれましたが、Vim script を皆に知って貰う為にはしっかりとした誘導書が必要なんだ、そんな風に思った事もありました。

そしてVimテクニックバイブル発売から3年、あの時にお世話になった技術評論社様にまたお力をお貸し頂き、今回「Vim scriptテクニックバイブル」という書籍の執筆をお手伝いをさせて頂きました。


Vim script テクニックバイブル ~Vim使いの魔法の杖 Vim script テクニックバイブル ~Vim使いの魔法の杖
Vim scriptサポーターズ
技術評論社 単行本(ソフトカバー) / ¥4,399 (2014年08月06日)
 
発送可能時間:


発売日は8/6です。

実は今回、Vim scriptサポーターズという著者名となっておりますが、かつてない程に Vim script に詳しい人間が揃いました。


Shougo

ご存じ「暗黒美夢王」です。色んな所で有名な Vimmer で、特に補完系のプラグインには絶大な拘りのある人です。

おそらく日本 Vim 界隈では年に一番 Vim script を書いている人だと思います。


thinca

こちらもご存じ「マンボウ」です。vim-jp では Vim script の挙動を一番良く知っている人だと思います。vimrc 読書会でも thinca さんの指摘内容は確実で、皆から「安心と信頼の thinca」と呼ばれています。(※要出典)

彼は基本的に Vim script を書くスピードは速くありません。しかし一つ一つが確実で、他の Vimmer に例を見ない程の慎重派です。だからこそ巷に溢れた vimrc に散乱するダメな Vim script には厳しく指摘が飛ぶのだと思います。


KoRoN

僕のこのブログをホストしている「香り屋」の店主であり、vim-jp 発起者でもあります。

十数年前から vim のバイナリ配布を始め、お世話になった Vimmer も多いと思います。僕もネット上でお付き合いを初めて10数年になりました。去年は大阪でお好み焼きを食べ、知り合った頃の懐かしい話等をさせて頂きました。

Vim の内部構造にめちゃくちゃ詳しい人です。vim-jp でもパッチ屋と呼ばれている部類の人です。

今回、書籍執筆のリーダとして仕切って頂きました。


Vim scriptテクニックバイブル

「これだけ揃えばもうお腹いっぱいだろ!」というメンツが揃い、実践的なテクニックを惜しげも無く記してあります。

人の vimrc からコピペして自分の vimrc を作るのは簡単です。しかし自分だけの Vim を作り上げる為には自分で vimrc を書く必要があるのです。

本書はテクニックバイブルという名前は付いていますが実際は

Vimmer が自分だけの Vim 探しを始める際に、お手伝いをする誘導書

的な存在となります。


ぜひお手に取って付箋紙をベタベタと貼って、自分だけの Vim を作り上げて下さい。

Posted at by



2014/07/09


前回、「幅跳び」が好評だったので、あの有名なゲーム「Flappy〇ird」を Vim で出来る flappyvird-vim を書いてみました。
mattn/flappyvird-vim ・ GitHub
https://github.com/mattn/flappyvird-vim
flappyvird
画像は開発中の物で、実際のキャラクタは異なります
良かったら遊んで下さい。
:FlappyVird でゲームスタート、スペースキーでジャンプ、p で一時停止、q もしくは ESC でゲーム終了です。
Posted at by