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);
  };
}