NAME

macro::JA - マクロプロセッサ

SYNOPSIS

use macro add => sub{ $_[0] + $_[1] };
say add(1, 3); # it's replaced into 'say do{ (1) + (3) };'

use macro sum => sub{ my $sum=0; for my $v(@_){ $sum+=$v }; $sum };
say sum(1, 2, 3); # => 6

use macro my_if => sub{ $_[0] ? $_[1] : $_[2] };
my_if( 0, print('true'), print('false') ); # only 'false' is printed

# or compile only
$ perl -c Module.pm # makes Module.pmc

DESCRIPTION

macroプラグマはCのプリプロセッサに似たマクロを提供する。 このマクロを呼び出すと,マクロのコードをマクロの呼び出し元に展開され, 関数呼び出しを伴わずにコードが実行される。このマクロ展開はコンパイル時に ソースフィルタリングメカニズムを通して行われる。また,ソースコードの解析にはPPI を用いている。

このマクロの呼び出しは非常に高速だが,Cプリプロセッサのマクロと同じ制限もある。たとえば, マクロの中でreturn()を呼ぶと期待通りには動作しない。マクロの定義は関数 の宣言のようにに見えるが,実際には関数のように動作するわけではない。

マクロが展開される様子は,環境変数PERL_MACRO_DEBUG2を指定することに よって知ることができる。

なお,マクロはレキシカルスコープである。

MACRO CALL

マクロの呼び出しは関数の呼び出しに似ており,マクロの名前の後に括弧で括った引数 リストを付けて呼び出す。引数リストの括弧を省略することはできない。

&を付けた関数呼び出しやアロー演算子によるメソッド呼び出しははマクロ呼び出しとは見做されないが, 間接オブジェクト構文によるメソッド呼び出しはマクロ呼び出しと区別がつかず,誤って展開される可能性がある。

なお,PPIの制限により,ダブルクォートの中の式展開や,s/regex/expr/eの式展開は パースされず,その結果マクロの展開も行われない。

MACRO ARGUMENTS

マクロの展開はCプリプロセッサに似ている。

マクロの定義において,@_$_[0]によってマクロの実引数を参照できる。 たとえば,$_[0]はマクロ呼び出しの第一引数に置き換えられる。 これは関数の引数に似ているが,実体はまったく異なり,@_のようなトークンを 実際の値に置き換えている。このとき,$_[0]というのはこれで単一のトークン として扱われ,添字として使えるのは単純な数値だけである。たとえば,$_[$i]は マクロの引数としては扱われず,マクロを呼び出した関数の引数を参照する。

Cプリプロセッサのマクロと同じく,$_[0]などのプレースホルダを参照しなければ 実引数は評価されず,プレースホルダを複数回参照すれば,実引数は複数回評価される。

また,Cプリプロセッサと違い,プレースホルダによって置き換えられる実引数 は常に単項プラス演算子が前に置かれ,括弧で囲まれる(つまり+(expr)となる)。 これは以下のようなマクロ定義を正しくおこなうためである。

use macro say => sub{ print @_, "\n" };
say('Hello, world!');

この引数のプレースホルダ@_は以下のように置き換えられる。

print +('Hello, world!'), "\n";

引数の扱いでは実行時のコンテキストが考慮されず,Cプリプロセッサのように 扱う点でも関数の呼び出しとは異なる。

use macro my_each => sub{ foreach ($_[0]) { $_[1] } };
my_each( (@a, @b, @c), say($_) );

これは以下のように置き換えられる。

foreach ( +(@a, @b, @c) ){ +(say($_)) }

また,ダブルクォートの中のプレースホルダ(@_)は置き換えられない。 以下のマクロの@_は展開されず,マクロの呼び出し元の引数が参照される。

use macro println => sub{ print "@_\n" }; # おそらく予想外の挙動

マクロの中ではpackageやプラグマの効果はなく,常に呼び出し元の環境の下で実行される。

BACKEND MODULE

このモジュールのバックエンドとして,macro::filtermacro::compilerが 存在する。デフォルトのバックエンドはmacro::compilerだが, 環境変数PERL_MACRO_DEBUG1を設定することで,macro::filterの 使用を強制できる。

macro::filterはソースフィルタとして働くため,スクリプトをロードする度に マクロ展開を行うが,余計なファイルを作成しない。

macro::compilerModule::Compileに似たスクリプトコンパイラとして動作し, ファイルの末尾にcが付加されたスクリプトファイルを生成する (たとえば,Foo.pmからはFoo.pmcが作られる)。Perlのuse Foo ディレクティブはFoo.pmcが存在すればFoo.pmcを読み込むので,コンパイル済み のスクリプトファイルは常に高速に動作する。また,コンパイルされたファイルは, オリジナルファイルの修正時間(mtime)に基づくチェックを行い,自動的に再コンパイル を行う。 オリジナルファイルはコンパイル済みファイルと同じディレクトリにあると仮定され, オリジナルファイルが見つからない場合はいかなるチェックも行われない。

perlを-cスイッチと共に使うことで,macro::compilerによるコンパイルのみを行う こともできる。

バックエンドモジュールをロード後に変更することはできないが,バックエンド モジュールを直接useすることはできる。

実行時の速度はどちらのバックエンドも変わらない。

PMC Support

macroを使うモジュールは,Module::Install::PMCを使ってインストールの前にモジュールをコンパイルすることができる。 そのためには,Makefile.PLに以下のように書けばよい。

use inc::Module::Install;
...
build_requires 'macro';
pmc_support;
...

Module::CompileModule::Install::PMCも参照せよ。

METHODS

macro->backend()

バックエンドモジュールの名前を返す。 これはmacro::filtermacro::compilerである。

macro::compilerバックエンドによってコンパイルされたファイルは,macro.pm をロードしないため,<macro-backend()>>を呼び出すことができないので注意せよ。

macro->new()

マクロプロセッサのインスタンス$macroを返す。

new(), defmacro(), process()はバックエンドモジュールを 実装するためのメソッドである。

$macro->defmacro(name => sub{ ... })

マクロプロセッサ$macroにマクロを定義する。

$macro->process($source)

Perlソースコード$sourceを受け取り,マクロ展開を行ったソースコードを返す。

CONFIGURATION AND ENVIRONMENT

PERL_MACRO_DEBUG=value

デバッグモードを設定する。

この値を指定しないか0であれば,macro::compilerがバックエンドとして使われる。

この値が1より大きければ,macro::filterがバックエンドとして使われる。

この値が2より大きければ,マクロの展開の様子がSTDERRに出力される。

INSTALL

To install this module, run the following commands:

perl Makefile.PL
make
make test
make install

DEPENDENCIES

  • Perl 5.8.1 or later.

  • PPI - Perl parser.

  • Filter::Util::Call - Source filter utility.

BUGS AND LIMITATIONS

No bugs have been reported.

Please report any bugs or feature requests to bug-macro@rt.cpan.org/, or through the web interface at http://rt.cpan.org/.

SEE ALSO

macro::filter - macro.pm source filter backend.

macro::compiler - macro.pm compiler backend.

AUTHOR

Goro Fuji <gfuji(at)cpan.org>.

LICENSE AND COPYRIGHT

Copyright (c) 2008-2009, Goro Fuji <gfuji(at)cpan.org>. Some rights reserved.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.