Mercurial > hg > Gears > Gears
view src/parallel_execution/generate_stub.pl @ 963:2e4c84f2683f
convert #interface into // include
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Thu, 18 Mar 2021 10:34:06 +0900 |
parents | 359f22dec55b |
children | 2caac93dee00 |
line wrap: on
line source
#!/usr/bin/perl use strict; use warnings; use Getopt::Long; use File::Path qw/make_path/; use File::Basename qw/basename dirname/; use Module::Load qw/load/; #use DDP { deparse => 1}; use FindBin; #FindBin::Bin is directory with generate_stub.pl use lib "$FindBin::Bin/lib"; #load Gears modules use Gears::Interface; use Gears::Util; use Gears::Stub; # interface.h # typedef struct Worker { # int id; # struct Context* contexts; # enum Code execute; # enum Code taskSend; # enum Code taskRecive; # enum Code shutdown; # struct Queue* tasks; # } Worker; our($opt_o,$opt_d,$opt_h, $opt_project, $opt_debug); GetOptions( "o=s" => \$opt_o, "d=s" => \$opt_d, "h" => \$opt_h, "project=s" => \$opt_project, "debug" => \$opt_debug, ); my $dir = "."; if ($opt_d) { $dir = $opt_d; if (! -d $dir) { make_path $dir; } } my %projects = ( gears => { cotnext => "context" }, xv6 => { context => "cbc_context" }, ); my $context_name = "context"; if ($opt_project && exists $projects{$opt_project}) { $context_name = $projects{$opt_project}->{context}; } my %var; my %code; my %dataGearVar; my %outputVar; # output var initializer my %outputArgs; # continuation's output variables my %dataGear; my %dataGearName; my %generic; my %dataGearVarType; my %codeGear; my %call_interfaces; my $headerNameToInfo = createHeaderNameToInfo($ARGV[0], $FindBin::Bin); my $searchCbCFromCodeGearNameWCurrentFrileName = createSearchCbCFromCodeGearNameWCurrentFrileName($FindBin::Bin); my %filename2EachCodeGearArgs; my %stub; my $implInterfaceInfo = {isImpl => undef, implementation => undef, interface => undef, parsedInterfaceInfo => undef, genConstructor => undef}; my $generateHaveOutputStub = { counter => undef, list => undef }; my $replaceCodeGearNames = {}; my $isGmain; my $constructorInfo = {}; # this for statement is main routine for my $fn (@ARGV) { next if ($fn !~ /\.cbc$/); my $cbc_content = slurpCbCFiles($fn); getDataGear($fn, $cbc_content); if ($isGmain) { $cbc_content = Gears::Stub->generate_new_main(cbc_path => $fn, cbc_content => $cbc_content); getDataGear($fn, $cbc_content); } if (%$constructorInfo) { #replace constructor $cbc_content = Gears::Stub->replaceConstructor($constructorInfo, $implInterfaceInfo, $cbc_content); } generateDataGear($fn, $cbc_content); } # interface definision # # typedef struct Stack<Type, Impl>{ # Type* stack; # Type* data; # Type* data1; # __code whenEmpty(...); # __code clear(Impl* stack,__code next(...)); # __code push(Impl* stack,Type* data, __code next(...)); # __code pop(Impl* stack, __code next(Type*, ...)); # __code pop2(Impl* stack, Type** data, Type** data1, __code next(Type**, Type**, ...)); # __code isEmpty(Impl* stack, __code next(...), __code whenEmpty(...)); # __code get(Impl* stack, Type** data, __code next(...)); # __code get2(Impl* stack,..., __code next(...)); # __code next(...); # } Stack; # # calling example # # goto nodeStack->push((union Data*)node, stackTest3); # # generated meta level code # # Gearef(context, Stack)->stack = (union Data*)nodeStack; # Gearef(context, Stack)->data = (union Data*)node; # Gearef(context, Stack)->next = C_stackTest3; # goto meta(context, nodeStack->push); sub getDataGear { my ($filename, @content) = @_; if (ref $content[0]) { @content = @{$content[0]}; } my ($lineNumber, $codeGearName, $name, $inTypedef,$described_data_gear, $currentCodeGear, $codeGearInfo); #open my $fd,"<",$filename or die("can't open $filename $!"); for (@content) { $lineNumber++; if (! $inTypedef) { #this scope is usually parsing cbc file if (/^typedef struct (\w+)\s*<(.*)>/) { debug_print("getDataGear",__LINE__, $_) if $opt_debug; $inTypedef = 1; $name = $1; $dataGear{$name} = $_; $var{$name} = {}; $code{$name} = {}; $generic{$name} = \split(/,/,$2); } elsif (/^typedef struct (\w+)/) { debug_print("getDataGear",__LINE__, $_) if $opt_debug; $inTypedef = 1; $name = $1; $dataGear{$name} = $_; $var{$name} = {}; $code{$name} = {}; $generic{$name} = []; #AtomicT<T> *createAtomicTImpl(struct Context* context, T init){ } elsif (/^(\w+)(?:<(\w+)>)?\s*(\*)\s*create(\w+)\(/) { # this case implementation constructor debug_print("getDataGear",__LINE__, $_) if $opt_debug; my $interfaceName = $1; # create.* function is constructor # However, other create.* function may not be a constructor # this case skip , other create.* function # But, I'm not thinking of a case with multiple constructors # (I think use array or hash...) if ($implInterfaceInfo->{interface}) { if ($implInterfaceInfo->{interface} ne $interfaceName) { next; } } $implInterfaceInfo->{isImpl} = 1; $implInterfaceInfo->{interface} = $interfaceName; $implInterfaceInfo->{implementation} = $4; my $cbc_source_path = $searchCbCFromCodeGearNameWCurrentFrileName->($interfaceName, $filename); if ($cbc_source_path) { # Probably not executed &getDataGear($cbc_source_path,slurpCbCFiles($cbc_source_path)); } $implInterfaceInfo->{genConstructor} = 0; $constructorInfo = Gears::Stub->parsedConstructor(\@content); } elsif(/^(.*)par goto (\w+)\((.*)\)/) { debug_print("getDataGear",__LINE__, $_) if $opt_debug; my $codeGearName = $2; my $cbc_source_path = $searchCbCFromCodeGearNameWCurrentFrileName->($codeGearName, $filename); if ($cbc_source_path) { &getCodeGear($cbc_source_path); } } elsif(/^#interface "(.*)"/) { debug_print("getDataGear",__LINE__, $_) if $opt_debug; # use interface my $interfaceHeader = $1; next if ($interfaceHeader =~ /context.h/); $interfaceHeader =~ m|(\w+)\.\w+$|; #remove filename extension my $interfaceName = $1; includeInterface(\%call_interfaces, $filename, $interfaceName, $headerNameToInfo); # #impl "Stack.h" as "SingleLinkedStack.h" } elsif(/^#impl "(.*?)"(?:\s+as\s+"(.*)")?/) { debug_print("getDataGear",__LINE__, $_) if $opt_debug; # use interface my $interfaceHeader = $1; my $implName = $2; $interfaceHeader =~ m|(\w+)\.\w+$|; #remove filename extension my $interfaceName = $1; includeInterface(\%call_interfaces, $filename, $interfaceName, $headerNameToInfo); my $interfacePATH = $headerNameToInfo->{$interfaceName}->{path}; unless ($implName) { $implName = basename $filename; } $implName =~ s/(\w+)\.\w+$/$1/; $implInterfaceInfo->{isImpl} = 1; $implInterfaceInfo->{interface} = $interfaceName; $implInterfaceInfo->{implementation} = $implName; $implInterfaceInfo->{genConstructor} = 1; $implInterfaceInfo->{parsedInterfaceInfo} = Gears::Interface->detailed_parse($interfacePATH); } elsif (/^\_\_code (\w+)\((.*)\)(.*)/) { debug_print("getDataGear",__LINE__, $_) if $opt_debug; my $codeGearName = $1; my $args = $2; if ($codeGearName =~ /_stub$/) { $stub{$codeGearName}->{static} = 1; $stub{$codeGearName}->{wrote} = 1; $currentCodeGear = undef; next; } if ($implInterfaceInfo->{parsedInterfaceInfo}) { if (exists_codegear_in_interface({codeGearName => $codeGearName, parsedInfo => $implInterfaceInfo->{parsedInterfaceInfo}})) { my $replaceCodeGear = "${codeGearName}$implInterfaceInfo->{implementation}"; #${pop}SingleLinkedStack $replaceCodeGearNames->{$codeGearName} = $replaceCodeGear; $codeGearName = $replaceCodeGear; } } my $cbc_source_path = $searchCbCFromCodeGearNameWCurrentFrileName->($codeGearName, $filename); if ($cbc_source_path) { &getCodeGear($cbc_source_path); } my $vname2type = Gears::Util->parseCodeGearDeclarationArg($args); for my $vname (keys %$vname2type) { $codeGearInfo->{$codeGearName}->{arg}->{$vname} = $vname2type->{$vname}; } $currentCodeGear = $codeGearName; if ($codeGearName =~ /gmain/ ) { $isGmain = 1; } } elsif ((/^\s*(union|struct|const|enum)?\s*([\w<>_*]+)(\*)\s+(\w+)\s+=/) && $currentCodeGear) { # collect local variables #StackGenerics<Integer>* generics_list = createStackGenericsImpl(); debug_print("getDataGear",__LINE__, $_) if $opt_debug; my $structType = $1 // ''; my $interfaceName = $2; my $pointer = $3; my $instance = $4; if ($interfaceName =~ /(\w+)<(\w+)>/) { #generics case $interfaceName = $1; } $codeGearInfo->{$currentCodeGear}->{localVar}->{$instance} = $interfaceName; } elsif (/^(.*)goto (\w+)\-\>(\w+)\((.*)\);/) { debug_print("getDataGear",__LINE__, $_) if $opt_debug; # handling goto statement # determine the interface you are using, and in the case of a goto CodeGear with output, create a special stub flag my $prev = $1; my $instance = $2; my $method = $3; my $tmpArgs = $4; my $typeName = $codeGearInfo->{$currentCodeGear}->{arg}->{$instance}; unless ($typeName) { #this case is not __code arguments. for my $localVar (keys %{$codeGearInfo->{$currentCodeGear}->{localVar}}) { if ($localVar eq $instance) { $typeName = $codeGearInfo->{$currentCodeGear}->{localVar}->{$localVar}; last; } } unless ($typeName){ die "[ERROR] not found $instance type at $lineNumber: $_\n"; } } unless (exists $call_interfaces{$filename}->{$typeName}) { warn "[AUTOINCLUDE] Forget #interface '$typeName' declaration in $filename"; includeInterface(\%call_interfaces, $filename, $typeName, $headerNameToInfo); } if ($implInterfaceInfo->{parsedInterfaceInfo}) { if (exists_codegear_in_interface({codeGearName => $tmpArgs, parsedInfo => $implInterfaceInfo->{parsedInterfaceInfo}})) { my $replaceCodeGear = "${tmpArgs}$implInterfaceInfo->{implementation}"; #${pop}SingleLinkedStack $tmpArgs = $replaceCodeGear; } } my $nextOutPutArgs = findExistsOutputDataGear($typeName, $method); my $outputStubElem = { modifyEnumCode => $currentCodeGear, createStubName => $tmpArgs }; if ($nextOutPutArgs) { my $tmpArgHash = {}; for my $vname (@$nextOutPutArgs) { $tmpArgHash->{$vname} = $typeName; } $outputStubElem->{args} = $tmpArgHash; #We're assuming that $tmpArgs only contains the name of the next CodeGear. #Eventually we need to parse the contents of the argument. (eg. @parsedArgs) my @parsedArgs = split /,/ , $tmpArgs; # if (scalar(@parsedArgs) != 1) { warn '[WARN] TBD'; } $generateHaveOutputStub->{counter}->{$tmpArgs}++; $outputStubElem->{counter} = $generateHaveOutputStub->{counter}->{$tmpArgs}; $generateHaveOutputStub->{list}->{$currentCodeGear} = $outputStubElem; } } elsif (/^}$/) { $currentCodeGear = undef; } next; } #this scope does parsing of header files # gather type name and type $dataGear{$name} .= $_; if (/^\s*(.*)\s+(\w+);$/ ) { debug_print("getDataGear",__LINE__, $_) if $opt_debug; my $ttype = $1; my $tname = $2; if (($ttype =~ /}/) && ($tname eq $name)) { # $_ == } StackGenerics; $inTypedef = 0; next; } if ($ttype =~ /^(union|struct|const|enum)\s*(\w+)/) { my $structType = $1; my $vname = $2; if ($structType ne 'const') { $ttype = $vname; } else { if ($structType =~ /(const|enum)/) { $ttype = "$structType $vname"; } } } $described_data_gear = 1; $var{$name}->{$tname} = $ttype; } if (/__code (\w+)/) { debug_print("getDataGear",__LINE__, $_) if $opt_debug; next if $described_data_gear; my $args = $'; my $tname2type = Gears::Util->parseCodeGearDeclarationArg($args); for my $tname (keys %$tname2type) { $var{$name}->{$tname} = $tname2type->{$tname}; } } if (/^}/) { debug_print("getDataGear",__LINE__, $_) if $opt_debug; $inTypedef = 0; } } if ($implInterfaceInfo->{isImpl} && $filename =~ /\.cbc\z/) { for my $shouldImplCode (map { $_->{name} } grep { $_->{args} =~ /Impl/ } @{$implInterfaceInfo->{parsedInterfaceInfo}->{codes}}) { my $isDefine = $shouldImplCode; for my $implCode (keys %{$codeGearInfo}) { if ($implCode =~ /$shouldImplCode/) { $isDefine = 1; next; } } if ($isDefine ne 1) { die "[ERROR] Not define $isDefine at $filename\n"; } } } $filename2EachCodeGearArgs{$filename} = $codeGearInfo; } sub includeInterface { my ($call_interfaces, $filename, $interfaceName, $headerNameToInfo) = @_; $call_interfaces->{$filename}->{$interfaceName} = 1; my $interface_path = $headerNameToInfo->{$interfaceName}->{path}; if ($interface_path) { getDataGear($interface_path, slurpCbCFiles($interface_path)); getCodeGear($interface_path); } } sub getCodeGear { my ($filename) = @_; open my $fd,"<",$filename or die("can't open $filename $!"); my ($name,$impln); while (<$fd>) { #AtomicT<T> *createAtomicTImpl(struct Context* context, T init){ if (/^(\w+)(<\w+>)?\s*(\*)+ create(\w+)\(/) { debug_print("getCodeGear",__LINE__, $_) if $opt_debug; $name = $1; $impln = $4; } elsif(/^typedef struct (\w+)\s*<.*>\s*{/) { debug_print("getCodeGear",__LINE__, $_) if $opt_debug; $name = $1; } if (defined $name) { if (/^\s*\_\_code (\w+)\((.*)\);/) { debug_print("getCodeGear",__LINE__, $_) if $opt_debug; my $args = $2; my $method = $1; $code{$name}->{$method} = []; while($args) { # replace comma $args =~ s/(^\s*,\s*)//; # continuation case if ($args =~ s/^(\s)*\_\_code\s+(\w+)\(([^)]*)\)//) { my $next = $2; my @args = split(/,/,$3); push(@{$code{$name}->{$method}},"\_\_code $next"); } elsif ($args =~ s/^(struct|union|const)?\s*(\w+)(\**)\s+(\w+)//) { my $structType = $1; my $typeName = $2; my $ptrType = $3; my $varName = $4; my $typeField = lcfirst($typeName); if ($structType && ($structType =~ /const/)) { $typeName = "$structType $typeName"; } push(@{$code{$name}->{$method}},"$typeName$ptrType $varName"); } elsif ($args =~ s/(.*,)//) { } else { last; } } } } elsif (/^\_\_code (\w+)\((.*)\)(.*)/) { debug_print("getCodeGear",__LINE__, $_) if $opt_debug; my $codeGearName = $1; my $args = $2; my $inputCount = 0; my $outputCount = 0; my $inputIncFlag = 1; while($args) { if ($args =~ s/(^\s*,\s*)//) { } if ($args =~ s/^(\s)*\_\_code\s+(\w+)\((.*?)\)//) { $codeGear{$codeGearName}->{"code"}->{$2} = "\_\_code"; $inputIncFlag = 0; my @outputs = split(/,/,$3); for my $output (@outputs) { if ($output =~ /\s*(struct|union|const)?\s*(\w+)(\*)?+\s(\w+)/) { my $structType = $1; my $type = $2; my $varName = $4; if ($structType =~ /const/) { $type = "$structType $type"; } $codeGear{$codeGearName}->{"var"}->{$varName} = "$type $outputCount"; $outputCount++; } } } elsif ($args =~ s/^(struct|union|const)?\s*(\w+)(\*)?+\s(\w+)// && $inputIncFlag) { my $structType = $1; my $type = $2; my $varName = $4; if ($structType =~ /const/) { $type = "$structType $type"; } $codeGear{$codeGearName}->{"var"}->{$varName} = "$type $inputCount"; $inputCount++; } elsif ($args =~ s/(.*,)//) { } else { last; } } $codeGear{$codeGearName}->{"input"} = $inputCount; $codeGear{$codeGearName}->{"output"} = $outputCount; } } } sub generateStub { my($fd,$prevCodeGearName,$dataGearName) = @_; print $fd "__code ", $prevCodeGearName ,"_stub(struct Context* $context_name) {\n"; print $fd $dataGearName; print $fd "\n}\n\n"; return 1; } sub generateImplStubArgs { my ($codeGearName, $varName, $typeName, $ptrType, $output, $interfaceName, $isImpl) = @_; return 0 unless $isImpl; for my $ivar (keys %{$var{$interfaceName}}) { # input data gear field if ($varName eq $ivar) { if ($typeName eq $var{$interfaceName}->{$ivar}) { if ($output) { $dataGearName{$codeGearName} .= "\t$typeName$ptrType* O_$varName = &Gearef($context_name, $interfaceName)->$varName;\n"; $outputVar{$codeGearName} .= "\t$typeName$ptrType $varName __attribute__((unused)) = *O_$varName;\n"; return 1; } $dataGearName{$codeGearName} .= "\t$typeName$ptrType $varName = Gearef($context_name, $interfaceName)->$varName;\n"; return 1; } } } # interface continuation for my $cName (keys %{$code{$interfaceName}}) { if ($varName eq $cName) { # continuation field $dataGearName{$codeGearName} .= "\tenum Code $varName = Gearef($context_name, $interfaceName)->$varName;\n"; return 1; } } } sub generateStubArgs { my($codeGearName, $varName, $typeName, $ptrType, $typeField, $implInterfaceInfo,$output) = @_; my $isImpl = $implInterfaceInfo->{isImpl}; my $interfaceName = $implInterfaceInfo->{interface}; my $implName = $implInterfaceInfo->{implementation}; my $varname1 = $output ? "O_$varName" : $varName; for my $n ( @{$dataGearVar{$codeGearName}} ) { # we already have it return 0 if ( $n eq $varname1); } push @{$dataGearVar{$codeGearName}}, $varname1; push @{$dataGearVarType{$codeGearName}}, $typeName; if ($isImpl){ if ($implName eq $typeName) { # get implementation $dataGearName{$codeGearName} .= "\t$typeName* $varName = ($typeName*)GearImpl($context_name, $interfaceName, $varName);\n"; return 1; } } return 1 if generateImplStubArgs($codeGearName, $varName, $typeName, $ptrType, $output, $interfaceName, $isImpl); # par goto var for my $var (keys %{$codeGear{$codeGearName}->{"var"}}) { # input data gear field if ($varName eq $var) { my ($type, $count) = split(/\s/, $codeGear{$codeGearName}->{"var"}->{$var}); if ($typeName eq $type) { if ($output) { $dataGearName{$codeGearName} .= "\t$typeName$ptrType* O_$varName = ($typeName $ptrType*)&${context_name}->data[${context_name}\->odg + $count];\n"; $outputVar{$codeGearName} .= "\t$typeName$ptrType $varName = *O_$varName;\n"; return 1; } $dataGearName{$codeGearName} .= "\t$typeName$ptrType $varName = &${context_name}->data[${context_name}\->idg + $count]->$typeName;\n"; return 1; } } } # par goto continuation for my $cName (keys %{$codeGear{$codeGearName}->{"code"}}) { if ($varName eq $cName) { # continuation field $dataGearName{$codeGearName} .= "\tenum Code $varName = ${context_name}\->next;\n"; return 1; } } # par goto continuation # global or local variable case if (($typeName eq "Code") && $isImpl) { $dataGearName{$codeGearName} .= "\tenum $typeName$ptrType $varName = Gearef(${context_name}, $interfaceName)->$varName;\n"; return 1; } if ($output) { $dataGearName{$codeGearName} .= "\t$typeName${ptrType}* O_$varName = &Gearef($context_name, $interfaceName)->$varName;\n"; } else { $dataGearName{$codeGearName} .= "\t$typeName$ptrType $varName = Gearef($context_name, $typeName);\n"; } return 1; } sub findExistsOutputDataGear { my ($interfaceName, $method) = @_; my $interfacePATH = $headerNameToInfo->{$interfaceName}->{path}; unless ($interfacePATH) { return undef; } my $parsedInterface = Gears::Interface->detailed_parse($interfacePATH); unless ($parsedInterface) { return undef; } unless (exists $parsedInterface->{hasOutputArgs}->{$method}) { return undef; } my $vname2types = $parsedInterface->{hasOutputArgs}->{$method}; my @outputArgs = keys %$vname2types; return \@outputArgs; } sub generateDataGear { my ($filename, $inputCbCFile) = @_; open my $in,"<",$filename or die("can't open $filename $!"); my $generateMeta = createGotoMetaFunction($filename); my $fn; if ($opt_o) { $fn = $opt_o; } else { my $fn1 = $filename; $fn1 =~ s/\.cbc/.c/; my $i = 1; $fn = "$dir/$fn1"; while ( -f $fn) { $fn = "$dir/$fn1.$i"; $i++; } } if ( $fn =~ m=(.*)/[^/]+$= ) { if (! -d $1) { make_path $1; } } open my $fd,">",$fn or die("can't write $fn $!"); my $prevCodeGearName; my $inTypedef = 0; my $inStub = 0; my $hasParGoto = 0; my $inMain = 0 ; my $inCode = 0 ; my $currentCodeGearName; my %localVarType; for (@$inputCbCFile){ if (! $inTypedef && ! $inStub && ! $inMain) { if (/^typedef struct (\w+)\s*\{/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; $inTypedef = 1; } elsif (/^int main\((.*)\) \{/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; $inMain = 1; #impl "Stack.h" as "SingleLinkedStack.h" } elsif(/^#impl "(.*)"\s*(?:as\s*"(\w+)")?/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; next unless ($implInterfaceInfo->{genConstructor}); if ($2 && ($implInterfaceInfo->{interface} ne $1)) { next; } my $constructInterface = { name => $implInterfaceInfo->{interface}, file_name => $headerNameToInfo->{$implInterfaceInfo->{interface}}->{path} }; my $constructImpl = { name => $implInterfaceInfo->{implementation}, file_name => $headerNameToInfo->{$implInterfaceInfo->{implementation}}->{path} }; unless ($constructImpl->{path}) { warn "[WARN] Not found $constructImpl->{name}.h"; } print $fd Gears::Stub->generate_constructor($constructInterface, $constructImpl, 1); # in c code generation mode, the last argument is 1. next; } elsif(/^#data (".*")/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; print $fd "// include $1\n"; next; } elsif(/^#interface "(.*)"/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; my $interfaceHeader = $1; # #interface not write print $fd "// include \"$1\"\n"; next unless ($interfaceHeader =~ /context.h/); } elsif (/^#include "(.*).h"$/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; my $headerName = $1; if ($headerName =~ m|/?context$|) { print $fd $_; next; } # This process assumes that there are no header files of the same name my $path = $headerNameToInfo->{$headerName}->{path}; unless ($path) { print $fd $_; next; } print $fd '#include "' .$path . '"'; print $fd "\n"; next; } elsif (/^\_\_code (\w+)\((.*)\)(.*)/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; $inCode = 1; %localVarType = (); $currentCodeGearName = $1; my $args = $2; my $tail = $3; #replace Code Gear Name to Implemenatation if (exists $replaceCodeGearNames->{$currentCodeGearName}) { $currentCodeGearName = $replaceCodeGearNames->{$currentCodeGearName}; } if ($currentCodeGearName =~ /_stub$/) { # don't touch already existing stub $inStub = 1; $stub{$currentCodeGearName}->{static} = 1; $stub{$currentCodeGearName}->{wrote} = 1; print $fd $_; next; } if (defined $prevCodeGearName) { # stub is generated just before next CodeGear if (defined $stub{$prevCodeGearName."_stub"}->{wrote}) { undef $prevCodeGearName; } else { &generateStub($fd,$prevCodeGearName,$dataGearName{$prevCodeGearName}); $stub{$prevCodeGearName."_stub"}->{wrote} = 1; } } # analyzing CodeGear argument # these arguments are extract from current context's argument DataGear Interface # and passed to the CodeGear # struct Implementation needs special handling # __code next(...) ---> enum Code next $prevCodeGearName = $currentCodeGearName; $dataGearVar{$currentCodeGearName} = []; $outputVar{$currentCodeGearName} = ""; $outputArgs{$currentCodeGearName} = {}; my $newArgs = "struct Context *${context_name},"; if ($args=~/^struct Context\s*\*\s*${context_name}/) { $newArgs = ""; } if (!$args){ $newArgs = "struct Context *${context_name}"; } while($args) { if ($args =~ s/(^\s*,\s*)//) { $newArgs .= $1; } # continuation case if ($args =~ s/^(\s)*\_\_code\s+(\w+)\(([^)]*)\)//) { my $next = $2; my @args = split(/,/,$3); if (generateStubArgs($currentCodeGearName, $next, "Code", "", $next, $implInterfaceInfo,0) ) { $newArgs .= "enum Code $next"; } # analyze continuation arguments # output arguments are defined in the Interface take the pointer of these # output arguments are put into the Interface DataGear just before the goto for my $arg (@args) { $arg =~ s/^\s*//; last if ($arg =~ /\.\.\./); $arg =~ s/^(struct|union|const|enum)?\s*(\w+)(\**)\s(\w+)//; my $structType = $1 // ''; my $typeName = $2; my $ptrType = $3; my $varName = $4; if ($structType =~ /(const|enum)/) { $typeName = "$structType $typeName"; } my $typeField = lcfirst($typeName); push(@{$outputArgs{$currentCodeGearName}->{$next}}, $varName); if (generateStubArgs($currentCodeGearName, $varName, $typeName, $ptrType, $typeField, $implInterfaceInfo,1)) { $newArgs .= ",$structType $typeName **O_$varName"; } } } elsif ($args =~ s/^(struct|union|const|enum)?\s*(\w+)(\**)\s(\w+)//) { my $structType = $1 // ''; my $typeName = $2; my $ptrType = $3; my $varName = $4; $newArgs .= $&; # assuming no duplicate if ($structType && ($structType =~ /(const|enum)/)) { $typeName = "$structType $typeName"; } my $typeField = lcfirst($typeName); generateStubArgs($currentCodeGearName, $varName, $typeName, $ptrType, $typeField, $implInterfaceInfo,0); } elsif ($args =~ s/(.*,)//) { $newArgs .= $1; } else { $newArgs .= $args; last; } } # generate goto statement from stub to the CodeGear in the buffer $dataGearName{$currentCodeGearName} .= "\tgoto $currentCodeGearName(${context_name}"; for my $arg ( @{$dataGearVar{$currentCodeGearName}}) { $dataGearName{$currentCodeGearName} .= ", $arg"; } $dataGearName{$currentCodeGearName} .= ");"; # generate CodeGear header with new arguments print $fd "__code $currentCodeGearName($newArgs)$tail\n"; if ($outputVar{$currentCodeGearName} ne "") { # output data var can be use before write # it should be initialze by gearef print $fd $outputVar{$currentCodeGearName}; } next; } elsif (! $inCode) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; s/new\s+(\w+)\(\)/\&ALLOCATE(${context_name}, $1)->$1/g; # replacing new print $fd $_; next; } elsif(/^(.*)par goto (\w+)\-\>(\w+)\((.*)\);/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; # handling par goto statement # convert it to the parallel # TODO my $prev = $1; my $instance = $2; my $method = $3; my $args = $4; my $currentCodeGearInfo = $filename2EachCodeGearArgs{$filename}->{$currentCodeGearName}; my $instanceType = $currentCodeGearInfo->{localVar}->{$instance}; my $currentInfo = $headerNameToInfo->{$instanceType}; my $parsedInstanceType = Gears::Interface->detailed_parse($currentInfo->{path}); my $inputCount = $parsedInstanceType->{codeName}->{$method}->{argc}; $inputCount--; # $inputCount == 1 means self my $outputCount = 0; if (keys %{$parsedInstanceType->{hasOutputArgs}}) { $outputCount = scalar(@{ keys %{$parsedInstanceType->{hasOutputArgs}} }); } my @iterateCounts; # parse examples 'par goto(.., iterate(10), exit);' if ($args =~ /iterate\((.*)?\),/) { @iterateCounts = split(/,/,$1);; $inputCount--; } # replace iterate keyword $args =~ s/iterate\((.*)?\),//; my @dataGears = split(/,\s*/, $args); my $nextCodeGear = pop(@dataGears); if (! $hasParGoto) { $hasParGoto = 1; print $fd "${prev}struct Element* element;\n"; } my $initTask = << "EOFEOF"; ${prev}${context_name}\->task = NEW(struct Context); ${prev}initContext(${context_name}\->task); ${prev}${context_name}\->task->next = ${instance}->${method}; ${prev}${context_name}\->task->idgCount = $inputCount; ${prev}${context_name}\->task->idg = ${context_name}\->task->dataNum; ${prev}${context_name}\->task->maxIdg = ${context_name}\->task->idg + $inputCount; ${prev}${context_name}\->task->odg = ${context_name}\->task->maxIdg; ${prev}${context_name}\->task->maxOdg = ${context_name}\->task->odg + $outputCount; EOFEOF print $fd $initTask; if (@iterateCounts) { print $fd "${prev}${context_name}\->task->iterate = 0;\n"; my $len = @iterateCounts; if ($len == 1) { print $fd "${prev}${context_name}\->task->iterator = createMultiDimIterator(${context_name}, $iterateCounts[0], 1, 1);\n"; } elsif ($len == 2) { print $fd "${prev}${context_name}\->task->iterator = createMultiDimIterator(${context_name}, $iterateCounts[0], $iterateCounts[1], 1);\n"; } elsif ($len == 3) { print $fd "${prev}${context_name}\->task->iterator = createMultiDimIterator(${context_name}, $iterateCounts[0], $iterateCounts[1], $iterateCounts[2]);\n"; } } if (@dataGears) { for my $dataGear (@dataGears) { print $fd "${prev}GET_META($dataGear)->wait = createSynchronizedQueue(${context_name});\n"; } } else { print $fd "${prev}GET_META($instance)->wait = createSynchronizedQueue(${context_name});\n"; } if ($inputCount > 1) { for my $i (0..$inputCount-1) { print $fd "${prev}${context_name}\->task->data[${context_name}\->task->idg+$i] = (union Data*)$dataGears[$i];\n"; } for my $i (0..$outputCount-1) { print $fd "${prev}${context_name}\->task->data[${context_name}\->task->odg+$i] = (union Data*)$dataGears[$inputCount+$i];\n"; } } my $parsed = { prev => $prev, next => $instance, method => $method, tmpArgs => $args, }; print $fd generateInterfaceGearef($_, $currentCodeGearName, $filename, $parsed, \%filename2EachCodeGearArgs, \%localVarType, "${context_name}->task"); my $putTask = << "EOFEOF"; ${prev}element = &ALLOCATE(${context_name}, Element)->Element; ${prev}element->data = (union Data*)${context_name}\->task; ${prev}element->next = ${context_name}\->taskList; ${prev}${context_name}\->taskList = element; EOFEOF print $fd $putTask; next; } elsif (/^(.*)goto (\w+)\-\>(\w+)\((.*)\);/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; # handling goto statement # convert it to the meta call form with two arguments, that is context and enum Code my $parsed = { prev => $1, next => $2, method => $3, tmpArgs => $4, }; print $fd generateInterfaceGearef($_, $currentCodeGearName, $filename, $parsed, \%filename2EachCodeGearArgs, \%localVarType, $context_name); my $next = "$parsed->{next}->$parsed->{method}"; print $fd $parsed->{prev},$generateMeta->($currentCodeGearName, $context_name, $next), "\n"; next; } elsif(/^(.*)par goto (\w+)\((.*)\);/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; # handling par goto statement # convert it to the parallel my $prev = $1; my $nextCodeGearName = $2; my $args = $3; my $inputCount = $codeGear{$nextCodeGearName}->{'input'}; my $outputCount = $codeGear{$nextCodeGearName}->{'output'}; my @iterateCounts; # parse examples 'par goto(.., iterate(10), exit);' if ($args =~ /iterate\((.*)?\),/) { @iterateCounts = split(/,/,$1);; $inputCount--; } # replace iterate keyword $args =~ s/iterate\((.*)?\),//; my @dataGears = split(/,\s*/, $args); my $nextCodeGear = pop(@dataGears); if (! $hasParGoto) { $hasParGoto = 1; print $fd "${prev}struct Element* element;\n"; } my $initTask = << "EOFEOF"; ${prev}${context_name}\->task = NEW(struct Context); ${prev}initContext(${context_name}\->task); ${prev}${context_name}\->task->next = C_$nextCodeGearName; ${prev}${context_name}\->task->idgCount = $inputCount; ${prev}${context_name}\->task->idg = ${context_name}\->task->dataNum; ${prev}${context_name}\->task->maxIdg = ${context_name}\->task->idg + $inputCount; ${prev}${context_name}\->task->odg = ${context_name}\->task->maxIdg; ${prev}${context_name}\->task->maxOdg = ${context_name}\->task->odg + $outputCount; EOFEOF print $fd $initTask; if (@iterateCounts) { print $fd "${prev}${context_name}\->task->iterate = 0;\n"; my $len = @iterateCounts; if ($len == 1) { print $fd "${prev}${context_name}\->task->iterator = createMultiDimIterator(${context_name}, $iterateCounts[0], 1, 1);\n"; } elsif ($len == 2) { print $fd "${prev}${context_name}\->task->iterator = createMultiDimIterator(${context_name}, $iterateCounts[0], $iterateCounts[1], 1);\n"; } elsif ($len == 3) { print $fd "${prev}${context_name}\->task->iterator = createMultiDimIterator(${context_name}, $iterateCounts[0], $iterateCounts[1], $iterateCounts[2]);\n"; } } for my $dataGear (@dataGears) { print $fd "${prev}GET_META($dataGear)->wait = createSynchronizedQueue(${context_name});\n"; } for my $i (0..$inputCount-1) { print $fd "${prev}${context_name}\->task->data[${context_name}\->task->idg+$i] = (union Data*)$dataGears[$i];\n"; } for my $i (0..$outputCount-1) { print $fd "${prev}${context_name}\->task->data[${context_name}\->task->odg+$i] = (union Data*)$dataGears[$inputCount+$i];\n"; } my $putTask = << "EOFEOF"; ${prev}element = &ALLOCATE(${context_name}, Element)->Element; ${prev}element->data = (union Data*)${context_name}\->task; ${prev}element->next = ${context_name}\->taskList; ${prev}${context_name}\->taskList = element; EOFEOF print $fd $putTask; next; } elsif (/^(.*)goto (\w+)\((.*)\);/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; # handling goto statement # convert it to the meta call form with two arguments, that is context and enum Code my $prev = $1; my $next = $2; my @args = split(/,/, $3); my $v = 0; my $arg_context = $context_name; if ($prev =~ /kernel/) { $prev = ""; $arg_context = "kernel"; } for my $n ( @{$dataGearVar{$currentCodeGearName}} ) { # continuation arguments $v = 1 if ( $n eq $next); } if (exists_codegear_in_interface({codeGearName => $next, parsedInfo => $implInterfaceInfo->{parsedInterfaceInfo}})) { my $replaceCodeGear = "${next}$implInterfaceInfo->{implementation}"; #${pop}SingleLinkedStack if ($replaceCodeGearNames->{$next}) { $next = $replaceCodeGear; } } if ($v || ($implInterfaceInfo->{isImpl} && defined $code{$implInterfaceInfo->{interface}}->{$next})) { # write continuation's arguments into the interface arguments # we may need a commit for a shared DataGear for my $arg ( @{$outputArgs{$currentCodeGearName}->{$next}} ) { my $v = shift(@args); print $fd "\t*O_$arg = $v;\n"; } if ($hasParGoto) { print $fd "${prev}Gearef(${arg_context}, TaskManager)->taskList = ${arg_context}->taskList;\n"; print $fd "${prev}Gearef(${arg_context}, TaskManager)->next1 = C_$next;\n"; print $fd ${prev},$generateMeta->($currentCodeGearName, ${arg_context}, "C_$next"), "\n"; } else { print $fd ${prev},$generateMeta->($currentCodeGearName, ${arg_context}, $next), "\n"; } next; } if ($hasParGoto) { print $fd "${prev}Gearef(${arg_context}, TaskManager)->taskList = ${arg_context}\->taskList;\n"; print $fd "${prev}Gearef(${arg_context}, TaskManager)->next1 = C_$next;\n"; print $fd "${prev}goto parGotoMeta(${arg_context}, C_$next);\n"; next; } elsif ($next eq "meta") { print $fd $_; next; } else { print $fd ${prev},$generateMeta->($currentCodeGearName, ${arg_context}, "C_$next"), "\n"; next; } } elsif(/^.*(struct|union)?\s([\w<>]+)\*\s(\w+)\s?[=;]/) { # TODO: FIX!! # see also comment local val collent #} elsif ((/^\s*(union|struct|const|enum)?\s*([\w<>]+)(\*)\s+(\w+)\s+=/) && $currentCodeGear) { # collect local variables debug_print("generateDataGear",__LINE__, $_) if $opt_debug; my $type = $2; my $varName = $3; if ($type =~ /(\w+)<(\w+)>/) { #generics case $type = $1; } $localVarType{$varName} = $type; s/new\s+(\w+)\(\)/\&ALLOCATE(${context_name}, $1)->$1/g; # replacing new } elsif(/^}/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; $hasParGoto = 0; } else { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; s/new\s+(\w+)\(\)/\&ALLOCATE(${context_name}, $1)->$1/g; # replacing new } # gather type name and type } elsif ($inMain) { if (/^(.*)goto start_code\(main_${context_name}\);/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; print $fd $_; next; } elsif (/^(.*)goto (\w+)\((.*)\);/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; my $prev = $1; my $next = $2; print $fd "${prev}struct Context* main_${context_name} = NEW(struct Context);\n"; print $fd "${prev}initContext(main_${context_name});\n"; print $fd "${prev}main_${context_name}->next = C_$next;\n"; print $fd "${prev}goto start_code(main_${context_name});\n"; next; } } if (/^}/) { debug_print("generateDataGear",__LINE__, $_) if $opt_debug; $inStub = 0; $inTypedef = 0; $inMain = 0; $inCode = 0; } print $fd $_; } if (defined $prevCodeGearName) { if (!defined $stub{$prevCodeGearName."_stub"}->{wrote}) { $stub{$prevCodeGearName."_stub"}->{wrote} = &generateStub($fd,$prevCodeGearName,$dataGearName{$currentCodeGearName}); } } #Create a stub when the output is a different interface for my $modifyEnumCodeCodeGear (keys %{$generateHaveOutputStub->{list}}) { my $outputStubElem = $generateHaveOutputStub->{list}->{$modifyEnumCodeCodeGear}; my $targetStubName = $outputStubElem->{createStubName}; my $createStubName = "$outputStubElem->{createStubName}_$outputStubElem->{counter}"; my $replaceArgs = $outputStubElem->{args}; my $replaceStubContents = $dataGearName{$targetStubName}; #If the stub was handwritten, skip if ($stub{"${targetStubName}_stub"}->{static}) { next; } for my $arg (keys %$replaceArgs) { my $interface = $replaceArgs->{$arg}; $replaceStubContents =~ s/,(.*)\)->$arg/, $interface)->$arg/; } generateStub($fd,$createStubName,$replaceStubContents); } } sub createHeaderNameToInfo { my ($fn, $search_root) = @_; my $dirname = dirname $fn; my $files = Gears::Util->find_headers_from_path($search_root); my $interface_name2headerpath = {}; #This process assumes that there are no header files of the same name for my $file (@{$files}) { if ($file =~ m|/(\w+)\.\w+$|) { my $file_name = $1; my $isInterface = Gears::Interface->isThisFileInterface($file); if (defined $interface_name2headerpath->{$file_name}) { next if ($file !~ m|$dirname|); } $interface_name2headerpath->{$file_name} = { path => $file, isInterface => $isInterface }; } } return $interface_name2headerpath; } sub create_cbc_name_to_source_path { # create this structure # # { # SemaphoreImpl.cbc [ # [0] "/Users/anatofuz/src/firefly/hg/Gears/Gears/src/parallel_execution/SemaphoreImpl.cbc", # [1] "/Users/anatofuz/src/firefly/hg/Gears/Gears/src/parallel_execution/examples/boundedBuffer/SemaphoreImpl.cbc" # ], # SingleLinkedQueue.cbc [ # [0] "/Users/anatofuz/src/firefly/hg/Gears/Gears/src/parallel_execution/SingleLinkedQueue.cbc" # ], # } my $search_root = shift; my $files = Gears::Util->find_cbc_sources_from_path($search_root); my $cbc_name2_source_path = {}; for my $file (@{$files}) { my $cbc_name = basename $file; $cbc_name =~ s/\.cbc//; push(@{$cbc_name2_source_path->{$cbc_name}},$file); } return $cbc_name2_source_path; } sub createSearchCbCFromCodeGearNameWCurrentFrileName { #Find the cbc file that contains CodeGear. #If there are more than one cbc file, the one whose namespace is the same as the filename has priority. my $search_root = shift; my $cbc_name2_source_path = create_cbc_name_to_source_path($search_root); # return sub is create clojure return sub { my ($codeGearName, $filename) = @_; my $cbc_files = $cbc_name2_source_path->{$codeGearName} // []; if (scalar(@{$cbc_files}) == 0) { # Not Found return 0; #false case } if (scalar(@{$cbc_files}) == 1) { # this case $codeGearName.cbc is single (SingleLinkedQueue.cbc) return $cbc_files->[0]; # return "/Users/anatofuz/src/firefly/hg/Gears/Gears/src/parallel_execution/SingleLinkedQueue.cbc" } my $cbc_dir_name = dirname $filename; for my $cbc_file (@{$cbc_files}) { if ($cbc_file =~ /$cbc_dir_name/) { return $cbc_file; } } return 0; # Not found } } sub get_indent_len { my $prev = shift; if ($prev =~ /^(\s+).*$/) { return $1; } return ""; } sub exists_codegear_in_interface { my $arg = shift; my $codeGearName = $arg->{codeGearName}; my $parsedInterfaceInfo = $arg->{parsedInfo}; my @res = grep { $_->{name} eq $codeGearName } @{$parsedInterfaceInfo->{codes}}; return @res; } sub slurpCbCFiles { my $cbcFile = shift; my @emitCbCFileArray; open my $fh, '<', $cbcFile or die "failed open $cbcFile"; while (<$fh>) { push(@emitCbCFileArray, $_); } close $fh; return \@emitCbCFileArray; } sub debug_print { my ($functionName, $lineNumber, $line) = @_; print "[$functionName] match $lineNumber : $line"; } sub generateInterfaceGearef { my ($line, $currentCodeGearName, $filename, $parsed, $filename2args, $localVarType, $context_name) = @_; my $return_line; my $prev = $parsed->{prev}; my $next = $parsed->{next}; my $method = $parsed->{method}; my $tmpArgs = $parsed->{tmpArgs}; my $indent = get_indent_len($prev); my $currentCodeGearInfo = $filename2args->{$filename}->{$currentCodeGearName}; #$tmpArgs =~ s/\(.*\)/\(\)/; my @args = split(/,/,$tmpArgs); if (! defined $dataGearVarType{$currentCodeGearName}) { return $line ; } my @types = @{$dataGearVarType{$currentCodeGearName}}; my $ntype; my $ftype; for my $v (@{$dataGearVar{$currentCodeGearName}}) { my $t = shift @types; if ($v eq $next || $v eq "O_$next") { $ntype = $t; $ftype = lcfirst($ntype); } } if (!defined $ntype) { $ntype = $localVarType->{$next}; $ftype = lcfirst($ntype); } $return_line .= "${indent}Gearef(${context_name}, $ntype)->$ftype = (union Data*) $next;\n"; # Put interface argument my $prot = $code{$ntype}->{$method}; my $i = 1; my $nextType = $currentCodeGearInfo->{localVar}->{$next} // $currentCodeGearInfo->{arg}->{$next}; my $nextTypePath = $headerNameToInfo->{$nextType}->{path}; my $parsedNextTypePath = Gears::Interface->detailed_parse($nextTypePath); unless (exists $parsedNextTypePath->{codeName}->{$method}) { die "[ERROR] not found $next definition at $_ in $filename\n"; } my $nextMethodInfo = $parsedNextTypePath->{codeName}->{$method}; my $nextMethodWantArgc = $nextMethodInfo->{argc}; if ($nextMethodWantArgc != scalar(@args)) { #use DDP {deparse => 1}; # p $nextMethodWantArgc; # p $nextMethodInfo; # p @args; die "[ERROR] invalid arg $line you shoud impl $nextMethodInfo->{args}\n"; } for my $arg (@args) { my $pType; my $pName; my $p = @$prot[$i]; next if ($p eq $arg); $p =~ s/^(.*)\s(\w+)//; $pType = $1; $pName = $2; $arg =~ s/^(\s)*(\w+)/$2/; if ($pType =~ s/\_\_code$//) { if ($arg =~ /(\w+)\(.*\)/) { $return_line .= "${indent}Gearef(${context_name}, $ntype)->$pName = $1;\n"; } else { my $hasGotoArgOrLocalVar = undef; my $outputStubElem = $generateHaveOutputStub->{list}->{$currentCodeGearName}; if ($implInterfaceInfo->{parsedInterfaceInfo}) { if (exists_codegear_in_interface({codeGearName => $arg, parsedInfo => $implInterfaceInfo->{parsedInterfaceInfo}})) { my $replaceCodeGear = "${arg}$implInterfaceInfo->{implementation}"; #${pop}SingleLinkedStack $arg = $replaceCodeGear; } } if ($outputStubElem && !$stub{$outputStubElem->{createStubName}."_stub"}->{static}) { my $pick_next = "$outputStubElem->{createStubName}_$outputStubElem->{counter}"; $return_line .= "${indent}Gearef(${context_name}, $ntype)->$pName = C_$pick_next;\n"; $i++; next; } # find __code of argument or local variable for my $localVType (qw/arg localVar/) { my $foundVarType = $currentCodeGearInfo->{$localVType}->{$arg}; if ($foundVarType && $foundVarType eq '__code') { $hasGotoArgOrLocalVar = 1; } } # inteface case if ($arg =~ /->/) { $return_line .= "${indent}Gearef(${context_name}, $ntype)->$pName = $arg;\n"; #Gearef->()->next = bar->baz; $i++; next; } if ($hasGotoArgOrLocalVar) { $return_line .= "${indent}Gearef(${context_name}, $ntype)->$pName = $arg;\n"; #Gearef->()->next = next; $i++; next; } $return_line .= "${indent}Gearef(${context_name}, $ntype)->$pName = C_$arg;\n"; $i++; next; } } elsif ($pType =~ /Data\**$/){ $return_line .= "${indent}Gearef(${context_name}, $ntype)->$pName = (union $pType) $arg;\n"; } else { $return_line .= "${indent}Gearef(${context_name}, $ntype)->$pName = $arg;\n"; } $i++; } return $return_line; } #my $goto_meta = "${prev}goto meta(${context_name}, $next->$method);\n"; sub generateDefaultgotoMeta { my (undef, $context, $next) = @_; return "goto meta($context, $next);"; } sub createGotoMetaFunction { my $filename = shift; my $project_dir_name = dirname $filename; my $metapm = "$FindBin::Bin/$project_dir_name/meta.pm"; unless (-f $metapm) { #default case return \&generateDefaultgotoMeta; } load $metapm; print "[info] load $metapm\n"; my @replaceMeta = meta->replaceMeta(); return sub { my ($currentCodeGearName, $context, $next) = @_; my $generator = shift @{[ map { $_->[1] } grep { $currentCodeGearName =~ $_->[0] } @replaceMeta ]}; unless ($generator) { return generateDefaultgotoMeta(undef, $context, $next); } return $generator->($context, $next); }; }