diff --git a/lib/Rubyish/Syntax/MethodCallWithBlock.pm b/lib/Rubyish/Syntax/MethodCallWithBlock.pm new file mode 100644 index 0000000..a8564fe --- /dev/null +++ b/lib/Rubyish/Syntax/MethodCallWithBlock.pm @@ -0,0 +1,38 @@ +package Rubyish::Syntax::MethodCallWithBlock; +use strict; +use warnings; +use 5.010; + +use B::Hooks::Parser; +use B::Hooks::EndOfScope; +use B::Generate; + +sub inject_close_paren { + my $linestr = B::Hooks::Parser::get_linestr; + my $offset = B::Hooks::Parser::get_linestr_offset; + substr($linestr, $offset, 0) = ');'; + B::Hooks::Parser::set_linestr($linestr); +} + +sub block_checker { + my ($op) = shift; + my $linestr = B::Hooks::Parser::get_linestr; + my $offset = B::Hooks::Parser::get_linestr_offset; + my $code = substr($linestr, $offset); + return unless $code ~~ /^->(?\w+)(\((?.*)\))?\s+{/; + $code = "->$+{method_name}($+{method_args}, sub { BEGIN { B::Hooks::EndOfScope::on_scope_end(\\&Rubyish::Syntax::MethodCallWithBlock::inject_close_paren); } "; + substr($linestr, $offset) = $code; + B::Hooks::Parser::set_linestr($linestr); +} + +sub import { + my ($class) = @_; + my $caller = caller; + B::Hooks::Parser::setup(); + my $linestr = B::Hooks::Parser::get_linestr(); + my $offset = B::Hooks::Parser::get_linestr_offset(); + substr($linestr, $offset, 0) = 'use B::Hooks::EndOfScope(); use B::OPCheck const => check => \&Rubyish::Syntax::MethodCallWithBlock::block_checker;'; + B::Hooks::Parser::set_linestr($linestr); +} + +1; diff --git a/t/method-call-with-block.t b/t/method-call-with-block.t new file mode 100644 index 0000000..3fa82bd --- /dev/null +++ b/t/method-call-with-block.t @@ -0,0 +1,24 @@ +#!/usr/bin/env perl -w +use strict; +use Test::More; + +use Rubyish::Syntax::MethodCallWithBlock; + +sub Foo::bar { + my ($self, $arg, $block) = @_; + $block->($arg); +} + +Foo->bar(42) { + pass "Foo->bar(): block is called"; +} +pass " no syntax error"; + +my $foo = bless {}, "Foo"; + +$foo->bar(42) { + pass '$foo->bar(): block is called'; +} +pass " no syntax error"; + +done_testing;