vim script でクラスの定義 その2
色々と考えた結果こんな感じになりました。
[ソース]
let g:type = accel#type#type() function! s:eval(class, expr, ...) let self = a:class if type(a:expr) == type(function("tr")) return call(a:expr, a:000, a:class) else return eval(a:expr) endif endfunction function! s:apply_def(class, def) let self = {} let self.class = a:class let self.def = a:def function! self.apply(...) let expr = self.def.join(map(copy(a:000),"s:type(v:val)"), "_") let expr = s:has_key(self.class, expr) ? expr : self.def return call("s:eval", [self.class, self.class[expr]] + a:000) endfunction return self endfunction function! s:has_key(dict, key) return type(a:dict) == type({}) ? has_key(a:dict, a:key) : 0 endfunction function! s:is_class(class) return s:has_key(a:class, "__type__") endfunction function! s:class(type) let self = {} let self.__type__ = "'".(a:type)."'" return self endfunction function! s:type(class) return s:is_class(a:class) \ ? s:apply_def(a:class, "__type__").apply() : g:type.name(a:class) " 型番号から文字列に変換 endfunction function! s:apply(class) let self = s:apply_def(a:class, "__apply__") return self endfunction function! s:bool(class) return s:apply_def(a:class, "__bool__").apply() endfunction function! s:string(class) return s:is_class(a:class) \ ? s:apply_def(a:class, "__string__").apply() : string(a:class) endfunction function! s:equal(class, other) return s:apply_def(a:class, "__equal__").apply(a:other) endfunction function! s:equal_type(a, b) return s:type(a:a) == s:type(a:b) endfunction function! s:plus(class, other) return s:apply_def(a:class, "__plus__").apply(a:other) endfunction " ----------------------------------------------------------------------------- " ユーザコード function! s:vec() let self = s:class("vec") let self.x = 0 let self.y = 0 let self.z = 0 function! self.__string__() return s:type(self)." : ".string([self.x, self.y, self.z]) endfunction function! self.__equal__vec(vec) return self.x == a:vec.x && self.y == a:vec.y && self.z == a:vec.z endfunction function! self.__equal__(value) return self.x == a:value && self.y == a:value && self.z == a:vec endfunction function! self.__plus__vec(vec) let result = deepcopy(a:vec) let result.x += self.x let result.y += self.y let result.z += self.z return result endfunction function! self.__plus__(value) let result = deepcopy(self) let result.x += a:value let result.y += a:value let result.z += a:value return result endfunction return self endfunction function! s:make_vec(x, y, z) let result = s:vec() let result.x += a:x let result.y += a:y let result.z += a:z return result endfunction function! s:main() let vec = s:make_vec(0, 0, 0) echo s:string(vec) let vec = s:plus(vec, 2) echo s:string(vec) let vec = s:plus(vec, s:make_vec(1, 2, 3)) echo s:string(vec) echo s:equal(vec, s:make_vec(3, 4, 5)) endfunction call s:main()
[出力]
vec : [0, 0, 0] vec : [2, 2, 2] vec : [3, 4, 5] 1
どことなく Python っぽい?ような?
vim script には演算子のオーバーロードの様な処理がないので、__string__ のような関数を定義して、s:string のような関数で、各処理が呼ばれるような形にしてみました。
演算子のオーバーロードが欲しいと思う辺り C++脳ですね。
あと辞書の関数名に波括弧(先日書いたオーバーライド云々の書き方)が使えないんですね…。
あちゃーどうしようかなぁー。まぁ直接書いちゃってもいいんだけども…ぐぬぬ…。
詳細は、help expr-entry 辺りを。
とりあえず、現状はこんな感じにする予定。
またちょくちょく変わるかも?