読者です 読者をやめる 読者になる 読者になる

Parser Combinator for Vim script

vim

Vim スクリプトでパーサコンビネータするライブラリを試しに書いてみた。とりあえずものすごく簡単な奴は動くようになったので公開してみる。

http://github.com/thinca/vim-vparsec

  • 絶賛実験バージョン。
    • インターフェースとかも完全に暫定版。
    • 全然最適化してない。
    • エラーメッセージも適当。
    • 多分中身の構成もいろいろおかしい。
  • そもそもこれで正しいのか作った本人もよくわかってない。
  • 大量に関数呼び出すので解析対象によっては 'maxfuncdepth' を大きめに設定する必要がある。

以下のように書ける。*1

" This is a sample for vparsec.vim

function! s:build_calculator()
  let p = vparsec#parsers()

  let conv = {}
  function! conv.expr(res)
    " res = [firstToken, [op, rhs]*]
    let [left, rest] = a:res
    for [op, right] in rest
      execute printf('let left = left %s right', op)
    endfor
    return left
  endfunction
  function! conv.term(res)
      return str2float(a:res)
  endfunction

  let number = p.regex('\v[+-]?\d+%(\.\d+%(e[+-]?\d+)?)?').named('number')
  let expr = p.lazy().named('expr')
  let term = p.or(number.map(conv.term), p.seq('(', expr, ')').at(1)).named('term')
  let mul = term.next(p.seq(p.or('*', '/'), term).many()).map(conv.expr).named('mul')
  let add = mul.next(p.seq(p.or('+', '-'), mul).many()).map(conv.expr).named('add')
  call expr.set(add)

  return expr.phrase()
endfunction

function! s:run_sample(calculator, input)
  let result = a:calculator.parse(a:input)
  if !result.successful
    return result.toString()
  endif
  return result.result
endfunction

echo s:run_sample(s:build_calculator(), '(2+4.2)*8+1.3-2*3+(3.1e2/2)')

結果。

199.9

おおおおお!動きましたね!

これはちょっと感動。あとはもう少し使いやすくなるようにあちこち弄っていきたいところ。全体的にイケてない箇所が多すぎる。
…実用性?何それおいしいの?

*1:コードは開発中のものです。