sub void(&) { $_[0]->(); () }
say context();
say scalar context();
say void { context() };
より高度なコードにより、より優れた構文が得られます。
use syntax qw( void );
say context();
say scalar context();
say void context();
余談ですが、以下はscalar
、コンパイル時のディレクティブほど関数ではないことを示しています。
$ diff -u0 \
<( perl -MO=Concise,-exec -Msyntax=void -E'say f()' 2>&1 ) \
<( perl -MO=Concise,-exec -Msyntax=void -E'say scalar f()' 2>&1 )
--- /dev/fd/63 2014-08-17 12:34:29.124827443 -0700
+++ /dev/fd/62 2014-08-17 12:34:29.128827401 -0700
@@ -7 +7 @@
-6 <1> entersub[t6] lKS/TARG <-- "l" for list context
+6 <1> entersub[t7] sKS/TARG <-- "s" for scalar context
同じことがuse syntax qw( void )
'sにも当てはまりvoid
ます:
$ diff -u0 \
<( perl -MO=Concise,-exec -Msyntax=void -E'say f()' 2>&1 ) \
<( perl -MO=Concise,-exec -Msyntax=void -E'say void f()' 2>&1 )
--- /dev/fd/63 2014-08-17 12:34:41.952692723 -0700
+++ /dev/fd/62 2014-08-17 12:34:41.952692723 -0700
@@ -7 +7 @@
-6 <1> entersub[t6] lKS/TARG <-- "l" for list context
+6 <1> entersub[t6] vKS/TARG <-- "v" for void context
仕組みuse syntax qw( void );
_
実際の作業はSyntax::Feature::VoidVoid.xs
によって行われ、その主要な行は次のとおりです。
STATIC OP* parse_void(pTHX_ GV* namegv, SV* psobj, U32* flagsp) {
return op_contextualize(parse_termexpr(0), G_VOID);
}
STATIC OP* ck_void(pTHX_ OP* o, GV* namegv, SV* ckobj) {
return remove_sub_call(o);
}
BOOT: {
const char voidname[] = "Syntax::Feature::Void::void";
CV* const voidcv = get_cvn_flags(voidname, sizeof(voidname)-1, GV_ADD);
cv_set_call_parser(voidcv, parse_void, &PL_sv_undef);
cv_set_call_checker(voidcv, ck_void, &PL_sv_undef);
}
void
を使用して sub を宣言しget_cvn
ます。(サブルーチンが定義されることはありません。) のコードはVoid.pm
、サブルーチンを呼び出し元のレキシカル スコープにエクスポートします。
void
を使用してユーザー定義の構文に従うように呼び出すことを Perl に伝えますcv_set_call_parser
。
void
を使用してコンパイルした後、呼び出しを操作する必要があることを Perl に伝えますcv_set_call_checker
。
Perl が の呼び出しに遭遇するとvoid
、ユーザー定義パーサーは用語 using を抽出し、用語parse_termexpr
のコンテキストを using に変更しvoid
ますop_contextualize
。
その後、チェッカーはvoid
引数 (項) を残しながら、オペコード ツリーから呼び出しを削除します。