├── Makefile ├── README.mkd ├── autoload └── lisper.vim ├── example ├── apply.lisp ├── bang.vim ├── fizzbuzz.lisp ├── http-get.lisp ├── list-add.lisp ├── loop.lisp ├── nest-loop.lisp ├── quote.lisp ├── system.lisp └── tak.lisp ├── lisper.vim.vimup ├── plugin └── lisper.vim └── unittest.vim /Makefile: -------------------------------------------------------------------------------- 1 | all : lisper-vim.zip 2 | 3 | remove-zip: 4 | -rm doc/tags 5 | -rm lisper-vim.zip 6 | 7 | lisper-vim.zip: remove-zip 8 | zip -r lisper-vim.zip autoload plugin doc example 9 | 10 | release: lisper-vim.zip 11 | vimup update-script lisper.vim 12 | -------------------------------------------------------------------------------- /README.mkd: -------------------------------------------------------------------------------- 1 | Lisper-Vim 2 | ========== 3 | 4 | This is lisper plugin. This vim plugin provide lisp environments for vimmers. 5 | 6 | **Lisp Machine** 7 | 8 | You can call lisper#eval() to evaluate expression. 9 | 10 | ```vim 11 | :echo lisper#eval('(+ 1 2 3 4 5)') 12 | 15 13 | ``` 14 | 15 | Or, make instance permanently. 16 | 17 | ```vim 18 | :let engine = lisper#engine() 19 | :echo engine.eval("(+ 1 2 3 4 5)") 20 | 15 21 | :echo engine.eval("(+ 1 (length (quote abc))") 22 | 4 23 | ``` 24 | 25 | The instance of lisp machine have global environment for the variable. 26 | 27 | **Repl for Lisp** 28 | 29 | You can run eval point loop in vim command-line. 30 | 31 | ```vim 32 | :LisperRepl 33 | ``` 34 | 35 | ```vim 36 | lisp> (length (quote abcde)) 37 | 5 38 | ``` 39 | 40 | **Author** 41 | 42 | Yasuhiro Matsumoto `` 43 | 44 | **Based Idea** 45 | 46 | This script based on 47 | -------------------------------------------------------------------------------- /autoload/lisper.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " lisper.vim 3 | " Author: Yasuhiro Matsumoto 4 | " Last Change: 21-Oct-2012. 5 | " 6 | " Based On: http://norvig.com/lis.py 7 | 8 | let s:env = { "bind": {}, "lambda": [] } 9 | 10 | function! s:env.new(...) 11 | let params = a:0 > 0 ? a:000[0] : [] 12 | let args = a:0 > 1 ? a:000[1] : [] 13 | let outer = a:0 > 2 ? a:000[2] : 0 14 | let f = 0 15 | while f < len(params) 16 | if exists("l:p") 17 | unlet p 18 | endif 19 | let p = params[f] 20 | let m = s:deref(p) 21 | let self.bind[m] = args[f] 22 | let f += 1 23 | endwhile 24 | let self.outer = outer 25 | return deepcopy(self) 26 | endfunction 27 | 28 | function! s:env.find(...) dict 29 | let var = a:1 30 | let is_set = a:0 > 1 ? a:2 : 0 31 | if is_set || has_key(self.bind, var) 32 | return self.bind 33 | endif 34 | if !empty(self.outer) 35 | return self.outer.find(var) 36 | endif 37 | throw "Not found symbol `".var."`" 38 | endfunction 39 | 40 | function! s:env.update(var) dict 41 | for k in keys(a:var) 42 | let self.bind[k] = a:var[k] 43 | endfor 44 | endfunction 45 | 46 | function! s:env.make_op(f, ...) dict 47 | let s:op_n = get(s:, 'op_n', 0) + 1 48 | let s:op_f{s:op_n}_ = a:f 49 | let s:op_f{s:op_n}__ = a:000 50 | function! s:op_f{s:op_n}(...) 51 | let __ = eval(substitute(expand(''), '^.*\zeop_f[0-9]\+$', 's:', '').'__') 52 | return eval(substitute(eval(substitute(expand(''), '^.*\zeop_f[0-9]\+$', 's:', '').'_'), '\n', '', 'g')) 53 | endfunction 54 | call add(self.lambda, 's:op_f'.s:op_n) 55 | return function('s:op_f'.s:op_n) 56 | endfunction 57 | 58 | function! s:env.make_do(f, ...) dict 59 | let s:op_n = get(s:, 'op_n', 0) + 1 60 | let s:op_f{s:op_n}_ = a:f 61 | let s:op_f{s:op_n}__ = a:000 62 | function! s:op_f{s:op_n}(...) 63 | let __ = eval(substitute(expand(''), '^.*\zeop_f[0-9]\+$', 's:', '').'__') 64 | exe eval(substitute(expand(''), '^.*\zeop_f[0-9]\+$', 's:', '').'_') 65 | endfunction 66 | call add(self.lambda, 's:op_f'.s:op_n) 67 | return function('s:op_f'.s:op_n) 68 | endfunction 69 | 70 | function! s:echo(...) 71 | echo join(a:000, ' ') 72 | return a:000 73 | endfunction 74 | 75 | function! s:echon(...) 76 | echon join(a:000, ' ') 77 | return a:000 78 | endfunction 79 | 80 | function! s:debug(...) 81 | echohl WarningMsg | echomsg string(a:000) | echohl None 82 | return a:000 83 | endfunction 84 | 85 | function! s:or(...) 86 | let a = [] 87 | for v in a:000 88 | let r = "" 89 | while v > 0 90 | let i = v % 2 91 | let r = i . r 92 | let v = v / 2 93 | endwhile 94 | call add(a, r) 95 | endfor 96 | let v = tr(eval(join(a, '-')), '2', '1') 97 | let i = 1 98 | let r = 0 99 | for n in reverse(split(v, '\zs')) 100 | if n == 1 101 | let r += i 102 | endif 103 | let i = i * 2 104 | endfor 105 | return r 106 | endfunction 107 | 108 | function! s:and(...) 109 | let a = [] 110 | for v in a:000 111 | let r = "" 112 | while v > 0 113 | let i = v % 2 114 | let r = i . r 115 | let v = v / 2 116 | endwhile 117 | call add(a, r) 118 | endfor 119 | let v = tr(eval(join(a, '-')), '21', '10') 120 | let i = 1 121 | let r = 0 122 | for n in reverse(split(v, '\zs')) 123 | if n == 1 124 | let r += i 125 | endif 126 | let i = i * 2 127 | endfor 128 | return r 129 | endfunction 130 | 131 | function! s:add_globals(env) 132 | "env.update(vars(math)) # sin, sqrt, ... 133 | let env = a:env 134 | call env.update({ 135 | \ '+': env.make_op('eval(join(map(range(a:0), ''"s:deref(a:".(v:val+1).")"''), ''+''))'), 136 | \ '-': env.make_op('eval(join(map(range(a:0), ''"s:deref(a:".(v:val+1).")"''), ''-''))'), 137 | \ '*': env.make_op('eval(join(map(range(a:0), ''"s:deref(a:".(v:val+1).")"''), ''*''))'), 138 | \ '/': env.make_op('eval(join(map(range(a:0), ''"s:deref(a:".(v:val+1).")"''), ''/''))'), 139 | \ 'not': env.make_op('!s:deref(a:1)'), 140 | \ '>': env.make_op('(s:deref(a:1) > s:deref(a:2))'), 141 | \ '<': env.make_op('(s:deref(a:1) < s:deref(a:2))'), 142 | \ '>=': env.make_op('(s:deref(a:1) >= s:deref(a:2))'), 143 | \ '<=': env.make_op('(s:deref(a:1) <= s:deref(a:2))'), 144 | \ '=': env.make_op('(s:deref(a:1) == s:deref(a:2))'), 145 | \ 'equal?': env.make_op('(s:deref(a:1) ==# s:deref(a:2))'), 146 | \ 'eq?': env.make_op('(s:deref(a:1) is# s:deref(a:2))'), 147 | \ 'length': env.make_op('len(s:deref(a:1))'), 148 | \ 'cons': env.make_op('eval(join(map(range(a:0), ''"s:deref(a:".(v:val+1).")"''), ''.''))'), 149 | \ 'car': env.make_op('s:deref(a:1)[0]'), 150 | \ 'cdr': env.make_op('s:deref(a:1)[1:]'), 151 | \ 'append': env.make_op('eval(join(map(map(copy(a:000), ''type(v:val)==3?v:val :[v:val]''), ''s:deref(v:val)''), ''+''))'), 152 | \ 'list': env.make_op('map(copy(a:000), ''s:deref(v:val)'')'), 153 | \ 'list?': env.make_op('type(s:deref(a:1))==3'), 154 | \ 'null?': env.make_op('len(s:deref(a:1)) == 0'), 155 | \ 'symbol?': env.make_op('type(a:1) == 4'), 156 | \ 'abs': env.make_op('abs(s:deref(a:1))'), 157 | \ 'sin': env.make_op('sin(s:deref(a:1))'), 158 | \ 'cos': env.make_op('cos(s:deref(a:1))'), 159 | \ 'tan': env.make_op('tan(s:deref(a:1))'), 160 | \ 'asin': env.make_op('asin(s:deref(a:1))'), 161 | \ 'acos': env.make_op('acos(s:deref(a:1))'), 162 | \ 'atan': env.make_op('atan(s:deref(a:1))'), 163 | \ 'atan2': env.make_op('atan2(s:deref(a:1), s:deref(a:2))'), 164 | \ 'mod': env.make_op('s:deref(a:1) % s:deref(a:2)'), 165 | \ 'floor': env.make_op('floor(s:deref(a:1))'), 166 | \ 'trunc': env.make_op('trunc(s:deref(a:1))'), 167 | \ 'and': env.make_op('call("s:and", a:000)'), 168 | \ 'or': env.make_op('call("s:or", a:000)'), 169 | \ '1'.'+': env.make_op('a:1+1'), 170 | \ '1'.'-': env.make_op('a:1-1'), 171 | \ '#t': !0, 172 | \ '#f': 0, 173 | \ 'nil': 0, 174 | \}) 175 | return env 176 | endfunction 177 | 178 | function! s:parse(s) 179 | let ctx = {"tokens": s:tokenize(a:s)} 180 | return s:read_from(ctx) 181 | endfunction 182 | 183 | function! s:can(r) 184 | let b = 0 185 | for s in a:r 186 | if s == '(' 187 | let b += 1 188 | elseif s == ')' 189 | let b -= 1 190 | endif 191 | endfor 192 | return b 193 | endfunction 194 | 195 | function! s:tokenize(s) 196 | let ss = split(a:s, '\zs') 197 | let [n, l] = [0, len(ss)] 198 | let r = [] 199 | let m = {"t": "\t", "n": "\n", "r": "\r"} 200 | while n < l 201 | let c = ss[n] 202 | if c =~ '[\r\n\t ]' 203 | let n += 1 204 | elseif c == '(' || c == ')' 205 | call add(r, c) 206 | let n += 1 207 | elseif c == '"' 208 | let b = c 209 | let n += 1 210 | while n < l 211 | let c = ss[n] 212 | if c == '"' 213 | let b .= c 214 | let n += 1 215 | break 216 | elseif c != '\' 217 | let b .= c 218 | elseif n < l - 1 && has_key(m, c) 219 | let b .= m[c] 220 | endif 221 | let n += 1 222 | endwhile 223 | call add(r, b) 224 | elseif c == ';' 225 | while n < l 226 | let c = ss[n] 227 | let n += 1 228 | if c == "\n" 229 | break 230 | endif 231 | endwhile 232 | else 233 | let b = '' 234 | while n < l 235 | let c = ss[n] 236 | if c =~ '[\r\n\t ()]' 237 | break 238 | endif 239 | let n += 1 240 | let b .= c 241 | endwhile 242 | call add(r, b) 243 | endif 244 | endwhile 245 | return r 246 | endfunction 247 | 248 | function! s:read_from(ctx) 249 | if len(a:ctx.tokens) == 0 250 | throw 'unexpected EOF while reading' 251 | endif 252 | let token = a:ctx.tokens[0] 253 | let a:ctx.tokens = a:ctx.tokens[1:] 254 | if '(' == token 255 | let l = [] 256 | while len(a:ctx.tokens) > 0 && a:ctx.tokens[0] != ')' 257 | call add(l, s:read_from(a:ctx)) 258 | endwhile 259 | if len(a:ctx.tokens) == 0 260 | throw 'unexpected EOF while reading' 261 | endif 262 | let a:ctx.tokens = a:ctx.tokens[1:] 263 | return l 264 | elseif ')' == token 265 | throw 'unexpected )' 266 | elseif token =~ "^'" 267 | if len(token) > 1 268 | return s:atom(token[1:]) 269 | else 270 | return ['quote'] + [s:read_from(a:ctx)] 271 | endif 272 | else 273 | return s:atom(token) 274 | endif 275 | endfunction 276 | 277 | function! s:atom(token) 278 | let t = type(a:token) 279 | if t == 0 || t == 5 280 | return a:token 281 | elseif t == 1 282 | if a:token =~ '^[+-]\?[0-9]\+$' 283 | return 0 + a:token 284 | endif 285 | if a:token =~ '^\([+-]\?\)\%([0-9]\|\.[0-9]\)[0-9]*\(\.[0-9]*\)\?\([Ee]\([+-]\?[0-9]+\)\)\?$' 286 | return str2float(a:token) 287 | endif 288 | if a:token =~ '^\".*"$' 289 | return eval(a:token) 290 | endif 291 | endif 292 | return {'_lisper_symbol_': a:token} 293 | endfunction 294 | 295 | function! lisper#stringer(v) 296 | let t = type(a:v) 297 | if t == 0 || t == 1 || t == 5 298 | return a:v 299 | elseif t == 4 300 | if has_key(a:v, '_lisper_symbol_') 301 | return lisper#stringer(a:v['_lisper_symbol_']) 302 | endif 303 | return string(a:v) 304 | elseif t == 3 305 | let s = '(' 306 | for V in a:v 307 | if s != '(' 308 | let s .= ' ' 309 | endif 310 | let s .= lisper#stringer(V) 311 | unlet V 312 | endfor 313 | let s .= ')' 314 | return s 315 | else 316 | return string(a:v) 317 | endif 318 | endfunction 319 | 320 | function! s:deref(x) 321 | let X = a:x 322 | while type(X) == 4 323 | if !has_key(X, '_lisper_symbol_') 324 | return X 325 | endif 326 | let Y = X['_lisper_symbol_'] 327 | unlet X 328 | let X = Y 329 | endwhile 330 | return X 331 | endfunction 332 | 333 | let s:lisp = {} 334 | 335 | function! s:lisp.dispose() dict 336 | for X in self.global_env.lambda 337 | exe "delfunction" X 338 | unlet X 339 | endfor 340 | let self.global_env = {} 341 | endfunction 342 | 343 | function! s:lisp._eval(...) dict abort 344 | let X = a:1 345 | let env = a:0 > 1 ? a:2 : self.global_env 346 | if type(X) == 4 " symbol 347 | let s = s:deref(X) 348 | if type(s) == 4 349 | return s 350 | endif 351 | return env.find(s)[s] 352 | elseif type(X) != 3 " constant 353 | return X 354 | else 355 | if len(X) == 0 356 | return 357 | endif 358 | if type(X) == 3 359 | let m = s:deref(X[0]) 360 | endif 361 | if type(m) != 1 362 | unlet m 363 | let m = '' 364 | endif 365 | if m == 'quote' " (quote exp) 366 | let [_, exp; rest] = X 367 | return exp 368 | elseif m == 'if' " (if test conseq alt) 369 | let [_, test, conseq; rest] = X 370 | let alt = len(rest) > 0 ? rest[0] : 0 371 | if self._eval(test, env) 372 | return self._eval(conseq, env) 373 | else 374 | return self._eval(alt, env) 375 | endif 376 | elseif m == 'set!' " (set! var exp) 377 | let [_, var, exp; rest] = X 378 | let m = s:deref(var) 379 | let vars = env.find(m, 1) 380 | let vars[m] = self._eval(exp, env) 381 | return m 382 | elseif m == 'define' " (define var exp) 383 | let [_, var, exp; rest] = X 384 | unlet m 385 | let m = s:deref(var) 386 | let env.bind[m] = self._eval(exp, env) 387 | return env.bind[m] 388 | elseif m == 'return' " (return exp) 389 | let env['_lisper_loop_'] = 0 390 | return len(X) > 1 ? self._eval(X[1], env) : 0 391 | elseif m == 'loop' " (loop exp*) 392 | let oldloop = get(env, '_lisper_loop_', 0) 393 | while 1 394 | for exp in X[1:] 395 | if exists("l:V") 396 | unlet V 397 | endif 398 | let env['_lisper_loop_'] = 1 399 | let V = self._eval(exp, env) 400 | if env['_lisper_loop_'] == 0 401 | let env['_lisper_loop_'] = oldloop 402 | return V 403 | endif 404 | unlet exp 405 | endfor 406 | endwhile 407 | elseif m == 'defun' " (defun func (var*) exp) 408 | let [_, proc, vars; rest] = X 409 | unlet m 410 | let m = s:deref(proc) 411 | let lvars = type(vars) == 3 ? vars : [vars] 412 | let lvt = len(lvars) > 0 ? s:deref(lvars[0]) : '' 413 | if len(lvars) == 2 && type(lvt) == 1 && lvt == '&rest' 414 | let lvars = lvars[1:] 415 | let env.bind[m] = {'_lisper_symbol_': env.make_op('__[0]._eval(__[1], s:env.new(__[2], [a:000], __[3]))', self, ["begin"]+rest, lvars, env)} 416 | else 417 | let env.bind[m] = {'_lisper_symbol_': env.make_op('__[0]._eval(__[1], s:env.new(__[2], a:000, __[3]))', self, ["begin"]+rest, lvars, env)} 418 | endif 419 | return env.bind[m] 420 | elseif m == 'let' " (let (var*) exp) 421 | let [_, vars; rest] = X 422 | let [lhs, rhs] = vars[0] 423 | return call(env.make_op('__[0]._eval(__[1], s:env.new(__[2], a:000, __[3]))', self, ["begin"]+vars[1:]+rest, [lhs], env), [rhs]) 424 | elseif m == 'lambda' " (lambda (var*) exp) 425 | let [_, vars; rest] = X 426 | let lvars = type(vars) == 3 ? vars : [vars] 427 | let lvt = len(lvars) > 0 ? s:deref(lvars[0]) : '' 428 | if len(lvars) == 2 && type(lvt) == 1 && lvt == '&rest' 429 | let lvars = lvars[1:] 430 | return {'_lisper_symbol_': env.make_op('__[0]._eval(__[1], s:env.new(__[2], [a:000], __[3]))', self, ["begin"]+rest, lvars, env)} 431 | else 432 | return {'_lisper_symbol_': env.make_op('__[0]._eval(__[1], s:env.new(__[2], a:000, __[3]))', self, ["begin"]+rest, lvars, env)} 433 | endif 434 | elseif m == 'apply' " (apply exp exp*) 435 | for exp in self._eval(X[2], env) 436 | if exists("l:VV") 437 | unlet VV 438 | endif 439 | let VV = self._eval(exp, env) 440 | if !exists("l:V") 441 | let V = VV 442 | else 443 | let V = call(self._eval(X[1]), [V, VV]) 444 | endif 445 | unlet exp 446 | endfor 447 | return V 448 | elseif m == 'begin' " (begin exp*) 449 | let V = 0 450 | for exp in X[1:] 451 | if exists("l:VV") 452 | unlet VV 453 | endif 454 | let VV = self._eval(exp, env) 455 | if exists("l:V") 456 | unlet V 457 | endif 458 | let V = VV 459 | unlet exp 460 | endfor 461 | return V 462 | elseif m == 'display' 463 | let exps = [] 464 | for exp in X[1:] 465 | call add(exps, self._eval(exp, env)) 466 | unlet exp 467 | endfor 468 | call call('s:echon', exps) 469 | return '' 470 | elseif m == 'newline' 471 | return self._eval(["display", "\n"] + X[1:], env) 472 | elseif m == 'vim-echo' || m == 'print' 473 | let exps = [] 474 | for exp in X[1:] 475 | call add(exps, self._eval(exp, env)) 476 | unlet exp 477 | endfor 478 | call call('s:echo', exps) 479 | return '' 480 | elseif m == 'vim-call' 481 | let exps = [] 482 | for exp in X[2:] 483 | call add(exps, self._eval(exp, env)) 484 | unlet exp 485 | endfor 486 | return call(s:deref(X[1]), exps) 487 | elseif m == 'vim-eval' 488 | let exps = [] 489 | for exp in X[2:] 490 | call add(exps, self._eval(exp, env)) 491 | unlet exp 492 | endfor 493 | return call(env.make_op(s:deref(X[1])), exps) 494 | elseif m == 'vim-do' 495 | let exps = [] 496 | for exp in X[2:] 497 | call add(exps, self._eval(exp, env)) 498 | unlet exp 499 | endfor 500 | return call(env.make_do(s:deref(X[1])), exps) 501 | else " (proc exp*) 502 | let exps = [] 503 | for exp in X 504 | call add(exps, self._eval(exp, env)) 505 | unlet exp 506 | endfor 507 | return call(s:deref(exps[0]), exps[1:]) 508 | endif 509 | endif 510 | endfunction 511 | 512 | function! s:lisp.eval(exp) dict 513 | try 514 | let old_maxfuncdepth = &maxfuncdepth 515 | set maxfuncdepth=2000 516 | return lisper#stringer(self._eval(s:parse(a:exp))) 517 | finally 518 | let &maxfuncdepth = old_maxfuncdepth 519 | endtry 520 | endfunction 521 | 522 | function! s:lisp.evalv(exp) dict 523 | return self._eval(s:parse(a:exp)) 524 | endfunction 525 | 526 | function! lisper#engine() 527 | let engine = deepcopy(s:lisp) 528 | let engine.global_env = s:add_globals(s:env.new()) 529 | return engine 530 | endfunction 531 | 532 | function! s:cut_vimprefix(e) 533 | let e = a:e 534 | if e =~ '^Vim' 535 | let e = substitute(e, '^Vim[^:]*:', '', '') 536 | endif 537 | return e 538 | endfunction 539 | 540 | function! lisper#eval(exp) 541 | let engine = lisper#engine() 542 | try 543 | return engine.eval(a:exp) 544 | catch /.../ 545 | throw s:cut_vimprefix(v:exception) 546 | finally 547 | call engine.dispose() 548 | unlet engine 549 | endtry 550 | endfunction 551 | 552 | function! lisper#repl() 553 | let repl = lisper#engine() 554 | let oldmore = &more 555 | set nomore 556 | let exp = '' 557 | let nest = 0 558 | try 559 | call repl.eval('(defun exit () (vim-do "throw ''exit''"))') 560 | while 1 561 | let prompt = "lisp".repeat(">", nest+1)." " 562 | let inp = input(prompt) 563 | let exp .= inp 564 | echo "\r".prompt.inp."\n" 565 | if len(exp) > 0 566 | let tokens = [] 567 | try 568 | let tokens = s:tokenize(exp) 569 | let ret = lisper#stringer(repl._eval(s:read_from({"tokens": tokens}))) 570 | echohl Constant | echo "=>" ret | echohl None 571 | let exp = '' 572 | let nest = 0 573 | catch /.../ 574 | if v:exception == 'exit' 575 | break 576 | elseif v:exception != 'unexpected EOF while reading' 577 | let exp = '' 578 | echohl WarningMsg | echo s:cut_vimprefix(v:exception) | echohl None 579 | else 580 | let exp .= ' ' 581 | let nest = s:can(tokens) 582 | endif 583 | finally 584 | if exists('ret') | unlet ret | endif 585 | endtry 586 | endif 587 | endwhile 588 | finally 589 | let &more = oldmore 590 | call repl.dispose() 591 | unlet repl 592 | endtry 593 | endfunction 594 | 595 | function! lisper#bang(s) 596 | try 597 | let bang = index(readfile(a:s), "LisperVimBang") 598 | if bang != -1 599 | call lisper#eval(join(getline(bang+2, '$'), "\n")) 600 | endif 601 | catch 602 | echohl WarningMsg | echo s:cut_vimprefix(v:exception) | echohl None 603 | endtry 604 | endfunction 605 | 606 | " vim:set et: 607 | -------------------------------------------------------------------------------- /example/apply.lisp: -------------------------------------------------------------------------------- 1 | (defun f (&rest args) (apply + args)) 2 | (f 1 2 3 4 5) 3 | -------------------------------------------------------------------------------- /example/bang.vim: -------------------------------------------------------------------------------- 1 | set nomore 2 | LisperVimBang 3 | 4 | (begin 5 | (set! i 0) 6 | (loop 7 | (if (= i 100) (return i)) 8 | (set! i (+ i 1)) 9 | (display (if (= (mod i 15) 0) 10 | "FizzBuzz" (if (= (mod i 5) 0) 11 | "Buzz" (if (= (mod i 3) 0) 12 | "Fizz" i)) 13 | ))(newline) 14 | ) 15 | ) 16 | 17 | ;; vim: set ft=lisp et: 18 | -------------------------------------------------------------------------------- /example/fizzbuzz.lisp: -------------------------------------------------------------------------------- 1 | (define i 0) 2 | (loop 3 | (if (= i 100) (return i)) 4 | (define i (+ i 1)) 5 | (display (if (= (mod i 15) 0) 6 | "FizzBuzz" (if (= (mod i 5) 0) 7 | "Buzz" (if (= (mod i 3) 0) 8 | "Fizz" i)) 9 | ))(newline) 10 | ) 11 | 12 | ;; vim: set ft=lisp et: 13 | -------------------------------------------------------------------------------- /example/http-get.lisp: -------------------------------------------------------------------------------- 1 | (define http-get 2 | (lambda (url) (vim-eval "webapi#http#get(a:1).content" url)) 3 | ) 4 | (define from-utf8 5 | (lambda (str) (vim-call "iconv" str "utf-8" (vim-eval "&encoding"))) 6 | ) 7 | (define html-parse 8 | (lambda (html) (vim-eval "webapi#html#parse(a:1)" html)) 9 | ) 10 | (define html-to-text 11 | (lambda (dom) (vim-eval "wwwrenderer#render_dom(a:1)" dom)) 12 | ) 13 | (html-to-text 14 | (html-parse (from-utf8 (http-get "http://mattn.kaoriya.net/"))) 15 | ) 16 | 17 | ;; vim: set ft=lisp et: 18 | -------------------------------------------------------------------------------- /example/list-add.lisp: -------------------------------------------------------------------------------- 1 | (define list-map (lambda (lhs rhs) (vim-call "map" lhs rhs))) 2 | (define list-add (lambda (lhs rhs) (vim-call "add" lhs rhs))) 3 | (set! l (quote (1 2 3))) 4 | (list-add l 4) 5 | (list-add l 5) 6 | (list-add l 6) 7 | (list-map l "'foo'.v:val") 8 | 9 | ;; vim: set ft=lisp: 10 | -------------------------------------------------------------------------------- /example/loop.lisp: -------------------------------------------------------------------------------- 1 | (set! i 10) 2 | (loop 3 | (if (= i 0) (return i)) 4 | (set! i (- i 1)) 5 | (vim-do " 6 | echo 'count down' a:1 7 | redraw 8 | sleep 1 9 | " i) 10 | ) 11 | (display "bomb!")(newline) 12 | 13 | ;; vim: set ft=lisp: 14 | -------------------------------------------------------------------------------- /example/nest-loop.lisp: -------------------------------------------------------------------------------- 1 | (set! i 10) 2 | (loop 3 | (if (= i 0) (return i)) 4 | (print "i" i) 5 | (set! j 10) 6 | (loop 7 | (print "j" j) 8 | (if (= j 0) (return j)) 9 | (set! j (- j 1)) 10 | ) 11 | (set! i (- i 1)) 12 | ) 13 | 14 | ;; vim: set ft=lisp: 15 | -------------------------------------------------------------------------------- /example/quote.lisp: -------------------------------------------------------------------------------- 1 | (print '(123)) 2 | -------------------------------------------------------------------------------- /example/system.lisp: -------------------------------------------------------------------------------- 1 | (define system (vim-eval "function('system')")) 2 | (system "ls -la ~/") 3 | ; or (vim-eval "system('ls')") 4 | ; or (vim-call "system" "ls") 5 | 6 | ;; vim: set ft=lisp: 7 | -------------------------------------------------------------------------------- /example/tak.lisp: -------------------------------------------------------------------------------- 1 | (defun tak(x y z) 2 | (if (<= x y) 3 | y 4 | (tak (tak (1- x) y z) 5 | (tak (1- y) z x) 6 | (tak (1- z) x y)))) 7 | (tak 6 3 0) 8 | -------------------------------------------------------------------------------- /lisper.vim.vimup: -------------------------------------------------------------------------------- 1 | script_name: Lisper.vim 2 | script_id: '3819' 3 | script_type: utility 4 | script_package: lisper-vim.zip 5 | script_version: '0.03' 6 | required_vim_version: '7.0' 7 | summary: Yet Another Lisp Engine 8 | 9 | detailed_description: | 10 | 11 | This vim plugin provide lisp environments for vimmers. 12 | 13 | Source Repository. 14 | ref: http://github.com/mattn/lisper-vim 15 | 16 | LisperEvalBuffer: evaluate buffer as lisp. 17 | LisperRepl: start repl in vim command-line. 18 | 19 | You can call lisper#eval() to evaluate expression. 20 | 21 | :echo lisper#eval('(+ 1 2 3 4 5)') 22 | 15 23 | 24 | Or, make instance permanently. 25 | 26 | :let engine = lisper#engine() 27 | :echo engine.eval("(+ 1 2 3 4 5)") 28 | 15 29 | :echo engine.eval("(+ 1 (length (quote abc))") 30 | 4 31 | 32 | The instance of lisp machine have global environment for the variable. 33 | 34 | install_details: | 35 | 36 | # cd ~/.vim 37 | # unzip lisper-vim.zip 38 | 39 | or if you install pathogen.vim: 40 | 41 | # cd ~/.vim/bundle # or make directory 42 | # unzip /path/to/lisper-vim.zip 43 | 44 | if you get sources from repository: 45 | 46 | # cd ~/.vim/bundle # or make directory 47 | # git clone http://github.com/mattn/lisper-vim.git 48 | 49 | versions: 50 | - '0.03': | 51 | This is an upgrade for Lisper.vim: 52 | [add] fix examples. 53 | - '0.02': | 54 | This is an upgrade for Lisper.vim: 55 | [add] added examples. 56 | - '0.01': | 57 | Initial upload 58 | 59 | # __END__ 60 | # vim: filetype=yaml 61 | -------------------------------------------------------------------------------- /plugin/lisper.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " File: lisper.vim 3 | " Author: Yasuhiro Matsumoto 4 | " Last Change: 03-Jul-2012. 5 | " Version: 0.03 6 | " 7 | command! LisperRepl call lisper#repl() 8 | command! LisperEvalLine echo lisper#eval(getline('.')) 9 | command! -range=% LisperEvalBuffer echo lisper#eval("(begin\n".join(getline(, ), "\n")."\n)") 10 | command! -range=% LisperEvalBufferWithoutOutput call lisper#eval("(begin\n".join(getline(, ), "\n")."\n)") 11 | command! LisperVimBang call lisper#bang(expand(''))|finish 12 | 13 | " vim:set et: 14 | -------------------------------------------------------------------------------- /unittest.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | let s:engine = lisper#engine() 4 | 5 | function! s:ss(s) 6 | if type(a:s) == 0 || type(a:s) == 5 7 | return string(a:s) 8 | endif 9 | let s = string(a:s) 10 | let s = substitute(s, '\n', '\\n', 'g') 11 | let s = substitute(s, '\r', '\\r', 'g') 12 | let s = substitute(s, '\t', '\\t', 'g') 13 | let s = substitute(s, "''", "'", 'g') 14 | if type(a:s) == 1 15 | let s = s[1:-2] 16 | endif 17 | return s 18 | endfunction 19 | 20 | function! s:test_equal(lhs, rhs) abort 21 | let ret = s:engine.eval(a:lhs) 22 | echo s:ss(a:lhs)."=>". s:ss(ret) 23 | if ret !=# a:rhs 24 | throw "failed: expected =>".s:ss(a:rhs) 25 | endif 26 | endfunction 27 | 28 | function! s:test_lambda(lhs) abort 29 | let ret = s:engine.evalv(a:lhs) 30 | echo a:lhs "=>" lisper#stringer(ret) 31 | if type(ret) != 4 32 | throw "failed: expected => function ref" 33 | endif 34 | endfunction 35 | 36 | try 37 | let s:more = &more 38 | set nomore 39 | call s:test_equal("12345678", "12345678") 40 | call s:test_equal("(quote 12345678)", "12345678") 41 | call s:test_equal("(quote lispl)", "lispl") 42 | call s:test_equal("(quote (a b c))", "(a b c)") 43 | call s:test_equal("(+ 1 2 3 4 5 6 7 8 9 10)", "55") 44 | call s:test_equal("(- 2 1 0)", "1") 45 | call s:test_equal("(* 3 3 3)", "27") 46 | call s:test_equal("(/ 50 5 10)", "1") 47 | call s:test_equal("(not 0)", "1") 48 | call s:test_equal("(> 1 2)", "0") 49 | call s:test_equal("(< 3 1)", "0") 50 | call s:test_equal("(>= 1 1)", "1") 51 | call s:test_equal("(<= 2 2)", "1") 52 | call s:test_equal("(= 10 10)", "1") 53 | call s:test_equal("(equal? (quote aaa) (quote aaa))", "1") 54 | call s:test_equal("(equal? 100 80)", "0") 55 | call s:test_equal("(length (quote aaa))", "3") 56 | call s:test_equal("(length (quote (a b c d e)))", "5") 57 | call s:test_equal("(car (quote (a b)))", "a") 58 | call s:test_equal("(cdr (quote (a b)))", "(b)") 59 | call s:test_equal("(append (quote (a b)) (quote c) (quote d) (quote (e f)))", "(a b c d e f)") 60 | call s:test_equal("(list 1 2 3 4 5 (quote (a b c)) 6 7 8 9 10)", "(1 2 3 4 5 (a b c) 6 7 8 9 10)") 61 | call s:test_equal("(list? 1)", "0") 62 | call s:test_equal("(list? (quote (1)))", "1") 63 | call s:test_equal("(null? (quote ()))", "1") 64 | call s:test_equal("(null? (quote (1)))", "0") 65 | call s:test_equal("(null? 10)", "0") 66 | call s:test_equal("(symbol? 10)", "0") 67 | call s:test_equal("(symbol? (quote a))", "1") 68 | call s:test_equal("(if (- 10 5) (quote then) (quote else))", "then") 69 | call s:test_equal("(if 0 (quote then) (quote else))", "else") 70 | call s:test_equal("(set! var (quote lispl))", "var") 71 | call s:test_equal("var", "lispl") 72 | call s:test_lambda("(define myadd (lambda (a b) (+ a b)))") 73 | call s:test_equal("(myadd 10 20)", "30") 74 | call s:test_equal("(begin (define mylist (lambda (a) (list var a))) (mylist var))", "(lispl lispl)") 75 | call s:test_equal("(cons \"hello\t\" \",こんにちわ\" \"\n世界\")", "hello\t,こんにちわ\n世界") 76 | call s:test_equal("(sin 0.3)", sin(0.3)) 77 | call s:test_equal("(cos 0.4)", cos(0.4)) 78 | call s:test_equal("(tan 0.5)", tan(0.5)) 79 | call s:test_equal("(asin 0.6)", asin(0.6)) 80 | call s:test_equal("(acos 0.7)", acos(0.7)) 81 | call s:test_equal("(atan 0.8)", atan(0.8)) 82 | call s:test_equal("(atan2 0.8 0.9)", atan2(0.8, 0.9)) 83 | call s:test_equal("(set! count 0)", "count") 84 | call s:test_equal("(loop (set! count (+ count 1)) (if (= 10 count) (return count)))", "10") 85 | call s:test_equal("((lambda var (+ (car var) (+ (car (cdr var)) 3))) 5 6)", "8") 86 | echohl Title | echo "SUCCEEDED" | echohl None 87 | catch 88 | echohl WarningMsg | echo "FAILED: " v:exception | echohl None 89 | finally 90 | let &more = s:more 91 | endtry 92 | 93 | " vi:set ts=8 sts=2 sw=2 tw=0: 94 | --------------------------------------------------------------------------------