LuaのパターンマッチングライブラリLPegを用いて四則演算の文法をパースする
前置き PandocでRedmineのwiki記法(textile)をGitLab Flavor Markdownに変換したかった しかしデフォルトのReaderだと完全な変換は不可能 Redmineのマクロに対応できない。特に {{collapse(...) ...}} マクロを折り畳み形式に変換したい パース後にLua filterで修正する方針もやろうとしたが、ASTの木構造を書き換えるレベルの修正が必要になり力尽きた 箇条書きの中に collapse が含まれているケースがきつい ところでPandocにはCustom Readerという機能があり、Luaを使って自分でReaderをかける Pandoc - Creating Custom Pandoc Readers in Lua LPegというライブラリを使えばBNFっぽい書き方で文法が書けて楽そう という経緯があり、まずLuaのLPegライブラリを勉強することにした。以下はその備忘録。 やること 四則演算の式を木構造(入れ子のテーブル構造)にパースすることが目的。 逆に、木構造に変換した後の処理はしない。例えば式を評価して計算値を出すことはここではやらない。 文法の正しさをチェックするために、ユニットテストを適宜書きながらコードを書いていく テスト駆動開発的にやっていく 免責事項 自分はLuaをほとんど書いたことがない。ほとんど雰囲気で書いており、何らかのベストプラクティスから外れている書き方をしている可能性がある。 LPegとは 公式サイト: LPeg - Parsing Expression Grammars For Lua PEG(Parsing Expression Grammer)がベースとなるパターンマッチングライブラリ。PEGというのは今回自分も初めて知った。どうやらCFG(Context Free Grammer; 文脈自由文法)とはまた別の形式文法らしい。 Parsing expression grammar - Wikipedia 「最初の解析がうまくいったらそれを、失敗なら次を順に試してゆき、成功したものを採用」という点がCFGとの違いの一つみたいで、これでCFGが持つ曖昧さを排除できるとか。 実行環境の準備 以下が入った環境を準備する。 Luaのインタプリタ Luaのライブラリ LPeg:PEG用のライブラリ busted:ユニットテスト用のライブラリ 一例: Nixで環境を用意する場合 Nix flakeで環境を準備する場合、以下を flake.nix として作成して nix develop コマンドを実行すれば、Luaの実行環境が作成される。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 { description = "A very basic flake"; inputs = { nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; in { devShells.default = pkgs.mkShell { packages = with pkgs; [ (lua.withPackages(ps: with ps; [ lpeg busted ])) ]; }; } ); } テスト環境の準備 メインのコードは main.lua に書くようにする テストは test.lua に書くようにする まず test.lua に以下を記載。main に含まれる add 関数(まだ未定義)のテストを試しに書いてみる。 ...