Во время поиска документации по незнакомым функциям стандартной библиотеки, наткнулся на удивительную фичу Perl’а — source filters. Она позволяет выполнять препроцессинг исходного кода перед выполнением. Обработка может производится как кодом на C, так и кодом на самом Perl’е, что является наиболее переносимым вариантом.
Так чего же он нам позволяет добиться?
Многого! Например можно добавить возможность использовать прототипы функций с именованными аргументами, которые появятся только в Perl6.
1 2 3 4 5 6 7 8 |
#!/usr/bin/perl use strict; use FunctionPrototype; sub myfunction($c, $d){ print "c: $c, d: $d\n"; } myfunction("arg1", "arg2"); |
Или изменить синтаксис чуть сильнее:
1 2 3 4 5 6 7 8 9 10 11 |
#!/usr/bin/perl use JavaLikePerl; /** * The HelloWorldApp class implements an application that * simply prints "Hello World!" to standard output. */ class HelloWorldApp { public static void main(String[] args) { System.out.println("Hello World!"); // Display the string. } } |
Код первого модуля:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package FunctionPrototype; use Filter::Util::Call; sub import { my ($type) = @_; my ($ref) = []; filter_add( bless $ref ); } sub filter { my ($self) = @_; my ($status); if ( ( $status = filter_read() ) > 0 ) { if( /^sub\s+(\w+)\((.*)\)\s*{\s*(#?.*)$/ ) { #Horrible regex to found function prototypes my($name, $args, $comment) = ($1,$2,$3); my @arguments = split /\s*,\s*/, $args; my $arguments_sigils = join '', map {substr($_, 0, 1)} @arguments; my $arguments_variables = join ', ', @arguments; $_ = "sub $name($arguments_sigils) { my($arguments_variables) = \@_; $comment\n"; } } $status; } 1; |
Основная цель которого преобразовывать строки вида:
1 |
sub myfunction($c, @d){ #comment |
в:
1 |
sub myfunction($@){ my ($c, @d) = @_; #comment |
Что позволяет этому коду исполняться, хотя без импорта этого модуля, возникаю ошибки:
Код второго модуля(очень «грязная» реализация — «просто чтобы работало»):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
package JavaLikePerl; use Filter::Util::Call; sub import { my ($type) = @_; my ($ref) = []; filter_add( bless $ref ); } sub filter { my ($self) = @_; my ($status); if ( ( $status = filter_read() ) > 0 ) { s!\/\*!=a!; s!\s*\*\/!=cut!; s/class (\w*)/package $1;/; s/public static void/sub/; s/String\[\] /\@/; s!//!#!; s!^}!}main\(\@ARGV\);!; s!System\.out\.println(.*);!print $1;print "\\n";!; if( /^sub\s+(\w+)\((.*)\)\s*{\s*(#?.*)$/ ) { #Horrible regex to found function prototypes my($name, $args, $comment) = ($1,$2,$3); my @arguments = split /\s*,\s*/, $args; my $arguments_sigils = join '', map {substr($_, 0, 1)} @arguments; my $arguments_variables = join ', ', @arguments; $_ = "sub $name($arguments_sigils) { my($arguments_variables) = \@_; $comment\n"; } } $status; } 1; |