Changeset 25966

Show
Ignore:
Timestamp:
12/05/08 20:03:57 (5 weeks ago)
Author:
tokuhirom
Message:

rewrite one file packer. work in progress. this is just a snapshot.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • lang/perl/HTTP-Engine/branches/mouse/tools/packto-onefile.pl

    r25937 r25966  
     1# ------------------------------------------------------------------------- 
     2# In the Moose world. 
     3# making attribute is too slow. 
     4# I want to preprocess it. 
     5# THIS IS PROOF OF CONCEPT!!!!! 
     6# ------------------------------------------------------------------------- 
    17use strict; 
    28use warnings; 
     
    915use HTTP::Engine::Interface::CGI; 
    1016use UNIVERSAL::require; 
     17use Data::Dumper; 
     18 
     19die "this script is its in alpha quality!do not use this script without tokuhirom!" unless $ENV{USER} ne 'tokuhirom'; 
    1120 
    1221my $PATH_TO_MOUSE_TINY = shift or die "Usage: $0 ../Mouse/lib/Mouse/Tiny.pm"; 
     
    3645); 
    3746 
    38 say "package HTTP::Engine::CGI;"; 
    39  
    40 # Mouse::Tiny 
    41 sub { 
    42     my $src = join '', read_file($PATH_TO_MOUSE_TINY); 
    43     say $src; 
    44 }->(); 
    45  
    46 # header 
    47 for (@files) { 
    48     say "\$INC{'$_'} = __FILE__;"; 
    49 } 
    50  
    51 # http::engine 
    52 for my $file (@files) { 
    53     my $src = join '', read_file("lib/$file"); 
    54     my $doc = PPI::Document->new(\$src); 
    55     $doc->prune('PPI::Token::Pod'); 
    56     $doc->prune('PPI::Token::Comment'); 
    57     $doc->find( 
    58         sub { 
    59             if ($_[1]->isa('PPI::Statement::Include')) { 
    60                 if ($_[1]->module =~ /^HTTP::Engine/) { 
    61                     eval { 
    62                         my $content = $_[1]->content; 
    63                         if ($content =~ /^use\s*(HTTP::Engine\S+)\s*(.*?);$/ms) { 
    64                             my ($pkg, $args) = ($1, $2); 
    65                             if ($pkg->can('import') && $pkg !~ /HTTP::Engine::(Util|Response|Request)/) { 
    66                                 my $token = PPI::Token::Word->new("BEGIN { ${pkg}::import('${pkg}', $args); }\n"); 
    67                                 $_[0]->__replace_child($_[1], $token); 
     47&main; exit; 
     48 
     49sub process_accessor { 
     50    my ($name, $klass, $attr) = @_; 
     51 
     52    my $self  = '$_[0]'; 
     53    my $key   = $name; 
     54    $name =~ s/^['"]//; 
     55    $name =~ s/['"]$//; 
     56 
     57    my $accessor = "{# attribute for $name\n"; 
     58    if ($attr->{trigger}) { 
     59        $accessor .= "my \$trigger = $attr->{trigger};\n"; 
     60    } 
     61    my $isa = $attr->{isa}; 
     62    if ($isa) { 
     63        $isa =~ s/^['"]//; 
     64        $isa =~ s/['"]$//; 
     65    } 
     66    if ($isa) { 
     67        if (Mouse::TypeRegistry->optimized_constraints()->{$isa}) { 
     68            $accessor .= "my \$constraint = Mouse::TypeRegistry->optimized_constraints()->{'$isa'};\n"; 
     69        } else { 
     70            $accessor .= "my \$constraint = sub { Mouse::Util::blessed(\$_) && Mouse::Util::blessed(\$_) eq '$isa' };\n"; 
     71        } 
     72    } 
     73    if (my $default = $attr->{default}) { 
     74        $accessor .= "my \$default = $attr->{default};\n"; 
     75    } 
     76    $accessor .= "sub $name {\n"; 
     77    if ($attr->{is} =~ /rw/) { 
     78        $accessor .= 'if (scalar(@_) >= 2) {' . "\n"; 
     79 
     80        my $value = '$_[1]'; 
     81 
     82        if ($isa) { 
     83            if ($attr->{coerce}) { 
     84                $accessor .= $value." = Mouse::TypeRegistry->typecast_constraints('$klass', '$isa', $value);"; 
     85            } 
     86            $accessor .= 'local $_ = '.$value.';'; 
     87            my $constraint = sub { }; 
     88            $accessor .= " 
     89                unless (\$constraint->()) { 
     90                    my \$display = defined(\$_) ? overload::StrVal(\$_) : \"undef\"; 
     91                    Carp::confess(\"Attribute ($name) does not pass the type constraint because: Validation failed for \\'$isa\\' failed with value \$display\"); 
     92            }" . "\n" 
     93        } 
     94 
     95        # if there's nothing left to do for the attribute we can return during 
     96        # this setter 
     97        $accessor .= 'return ' if !$attr->{weak_ref} && !$attr->{trigger} && !$attr->{auto_deref}; 
     98 
     99        $accessor .= $self.'->{'.$key.'} = '.$value.';' . "\n"; 
     100 
     101        if ($attr->{weak_ref}) { 
     102            $accessor .= 'Mouse::Util::weaken('.$self.'->{'.$key.'}) if ref('.$self.'->{'.$key.'});' . "\n"; 
     103        } 
     104 
     105        die "This module doesn't support trigger" if $attr->{trigger}; 
     106 
     107        $accessor .= "}\n"; 
     108    } 
     109    else { 
     110        $accessor .= 'Carp::confess "Cannot assign a value to a read-only accessor" if scalar(@_) >= 2;' . "\n"; 
     111    } 
     112 
     113    if ($attr->{lazy}) { 
     114        $accessor .= $self.'->{'.$key.'} = '; 
     115 
     116        $accessor .= $attr->{builder} 
     117                ? $self.'->$builder' 
     118                    : ref($attr->{default}) eq 'CODE' 
     119                    ? '$default->('.$self.')' 
     120                    : '$default'; 
     121        $accessor .= ' if !exists '.$self.'->{'.$key.'};' . "\n"; 
     122    } 
     123 
     124    if ($attr->{auto_deref}) { 
     125        die "THIS MODULE DOESN'T SUPPORT DEREF"; 
     126    } 
     127 
     128    $accessor .= 'return '.$self.'->{'.$key.'}; 
     129        } 
     130    }'; 
     131    $accessor; 
     132} 
     133 
     134sub generate_constructor_method_inline { 
     135    my ($klass, $attrs) = @_; 
     136    my @attrs = @$attrs; 
     137 
     138    my $buildargs = _generate_BUILDARGS(); 
     139    my $processattrs = _generate_processattrs($klass, \@attrs); 
     140 
     141    <<"..."; 
     142    sub new { 
     143        my \$class = shift; 
     144        my \$args = $buildargs; 
     145        my \$instance = bless {}, \$class; 
     146        $processattrs; 
     147        return \$instance; 
     148    } 
     149... 
     150} 
     151 
     152sub _generate_processattrs { 
     153    my ($class, $attrs) = @_; 
     154    my @res; 
     155    for my $attr (@$attrs) { 
     156        my $set_value = do { 
     157            my @code; 
     158 
     159            if ($attr->{coerce}) { 
     160                push @code, "my \$value = Mouse::TypeRegistry->typecast_constraints('$class', $attr->{isa}, \$args->{'$attr->{name}'});"; 
     161            } 
     162            else { 
     163                push @code, "my \$value = \$args->{'$attr->{name}'};"; 
     164            } 
     165 
     166            # this one is very slow. skip this in cgi mode. 
     167#           if ($attr->{isa}) { 
     168#               push @code, "\$attrs[$index]->verify_type_constraint( \$value );"; 
     169#           } 
     170 
     171            push @code, "\$instance->{'$attr->{name}'} = \$value;"; 
     172 
     173            if ($attr->{weak_ref}) { 
     174                push @code, "Mouse::Util::weaken( \$instance->{'$attr->{name}'} ) if ref( \$value );"; 
     175            } 
     176 
     177            if ( $attr->{trigger} ) { 
     178                die "this module doesn't support trigger"; 
     179            } 
     180 
     181            join "\n", @code; 
     182        }; 
     183 
     184        my $make_default_value = do { 
     185            my @code; 
     186 
     187            if ( $attr->{default} || $attr->{builder} ) { 
     188                unless ( $attr->{lazy} ) { 
     189                    push @code, "my \$value = "; 
     190 
     191                    if ($attr->{coerce}) { 
     192                        push @code, "Mouse::TypeRegistry->typecast_constraints('$class', $attr->{isa}, "; 
     193                    } 
     194 
     195                        if ($attr->{builder}) { 
     196                            push @code, "\$instance->$attr->{builder}"; 
     197                        } 
     198                        elsif (ref($attr->{default}) =~ /^sub /) { 
     199                            push @code, "@{[ $attr->{default} ]}->()"; 
     200                        } 
     201                        else { 
     202                            push @code, "$attr->{default}"; 
     203                        } 
     204 
     205                    if ($attr->{coerce}) { 
     206                        push @code, ");"; 
     207                    } 
     208                    else { 
     209                        push @code, ";"; 
     210                    } 
     211 
     212                    if ($attr->{isa}) { 
     213                        # "this module doesn't use type constraints"; 
     214                    } 
     215 
     216                    push @code, "\$instance->{'$attr->{name}'} = \$value;"; 
     217 
     218                    if ($attr->{weak_ref}) { 
     219                        push @code, "weaken( \$instance->{'$attr->{name}'} ) if ref( \$value );"; 
     220                    } 
     221                } 
     222                join "\n", @code; 
     223            } 
     224            else { 
     225                if ( $attr->{required} ) { 
     226                    qq{Carp::confess("Attribute ($attr->{name}) is required");}; 
     227                } else { 
     228                    "" 
     229                } 
     230            } 
     231        }; 
     232        my $code = <<"..."; 
     233            { 
     234                if (exists(\$args->{'$attr->{name}'})) { 
     235                    $set_value; 
     236                } else { 
     237                    $make_default_value; 
     238                } 
     239            } 
     240... 
     241        push @res, $code; 
     242    } 
     243    return join "\n", @res; 
     244} 
     245 
     246sub _generate_BUILDARGS { 
     247    <<'...'; 
     248    do { 
     249        if ( scalar @_ == 1 ) { 
     250            if ( defined $_[0] ) { 
     251                ( ref( $_[0] ) eq 'HASH' ) 
     252                || Carp::confess "Single parameters to new() must be a HASH ref"; 
     253                +{ %{ $_[0] } }; 
     254            } 
     255            else { 
     256                +{}; 
     257            } 
     258        } 
     259        else { 
     260            +{@_}; 
     261        } 
     262    }; 
     263... 
     264} 
     265 
     266sub replace_node { 
     267    my ($parent, $child, $src) = @_; 
     268    my $token = PPI::Token::Word->new($src); 
     269    $parent->__replace_child($child, $token); 
     270} 
     271 
     272sub main { 
     273    say "package HTTP::Engine::CGI;"; 
     274 
     275    # Mouse::Tiny 
     276    sub { 
     277        my $src = join '', read_file($PATH_TO_MOUSE_TINY); 
     278        say $src; 
     279    }->(); 
     280 
     281    # header 
     282    for (@files) { 
     283        say "\$INC{'$_'} = __FILE__;"; 
     284    } 
     285 
     286    # http::engine 
     287    for my $file (@files) { 
     288        my $src = join '', read_file("lib/$file"); 
     289        my $doc = PPI::Document->new(\$src); 
     290        $doc->prune('PPI::Token::Pod'); 
     291        $doc->prune('PPI::Token::Comment'); 
     292        # call ->import(); 
     293        $doc->find( 
     294            sub { 
     295                if ($_[1]->isa('PPI::Statement::Include')) { 
     296                    if ($_[1]->module =~ /^HTTP::Engine/) { 
     297                        eval { 
     298                            my $content = $_[1]->content; 
     299                            if ($content =~ /^use\s*(HTTP::Engine\S+)\s*(.*?);$/ms) { 
     300                                my ($pkg, $args) = ($1, $2); 
     301                                if ($pkg->can('import') && $pkg !~ /HTTP::Engine::(Util|Response|Request)/) { 
     302                                    replace_node($_[0], $_[1], "BEGIN { ${pkg}::import('${pkg}', $args); }\n"); 
     303                                } else { 
     304                                    $_[1]->delete; 
     305                                } 
    68306                            } else { 
    69                                 $_[1]->delete; 
     307                                warn "WTF? $content"; 
    70308                            } 
     309                        }; 
     310                        warn $@ if $@; 
     311                    } 
     312                } 
     313                return; 
     314            } 
     315        ); 
     316        (my $klass = $file) =~ s!/!::!g; 
     317        $klass =~ s!\.pm$!!; 
     318        my @attrs; 
     319        $doc->find( 
     320            sub { 
     321                eval { 
     322                    if ($_[1]->isa('PPI::Statement') && $_[1] =~ /^has/ && $_[1] !~ /\$attr/) { 
     323                        warn "WHY?" unless $_[1]->schild(0) eq 'has'; 
     324                        my $name = $_[1]->schild(1)->content; 
     325                        my ($args, ) = @{ $_[1]->find('PPI::Statement::Expression') || [] } or die "missing expression"; 
     326                        my @args = $args->children; 
     327                        my $expect_key = 1; 
     328                        my @args_result; 
     329                        while (my $elem = shift @args) { 
     330                            next if $elem->isa('PPI::Token::Whitespace'); 
     331                            next if $elem->isa('PPI::Token::Operator'); 
     332 
     333                            if ($expect_key) { 
     334                                push @args_result, "$elem"; 
     335                                $expect_key = 0; 
     336                            } else { 
     337                                if ($elem->isa('PPI::Token::Word') && $elem eq 'sub') { 
     338                                    my $content; 
     339                                    while (my $block = shift @args) { 
     340                                        next if $block->isa('PPI::Token::Whitespace'); 
     341                                        unless ($block->isa('PPI::Structure::Block')) { 
     342                                            warn "invalid token: @{[ ref $block ]} $elem, $block ,$_[1]"; 
     343                                            warn join '    ---- ', @args; 
     344                                            exit; 
     345                                        } 
     346                                        $content = "sub $block"; 
     347                                        last; 
     348                                    } 
     349                                    push @args_result, $content; 
     350                                } else { 
     351                                    push @args_result, "$elem"; 
     352                                } 
     353                                $expect_key = 1; 
     354                            } 
     355                        } 
     356 
     357                        $name =~ s/^['"]//; 
     358                        $name =~ s/['"]$//; 
     359                        my $attr = {@args_result, name => $name}; 
     360                        my $src = process_accessor($name, $klass, $attr) . "\n"; 
     361                        if (my $handles = $attr->{handles}) { 
     362                            my $handles = eval $handles; 
     363                            die $@ if $@; 
     364                            for my $handle (@$handles) { 
     365                                $handle =~ s/^['"]//; 
     366                                $handle =~ s/['"]$//; 
     367                                $src .= "sub $handle { shift->$name->$handle(\@_) }\n"; 
     368                            } 
     369                        } 
     370                        eval $src; 
     371                        if ($@) { 
     372                            warn "------------- START"; 
     373                            warn $@; 
     374                            warn $src; 
     375                            warn "------------- END"; 
    71376                        } else { 
    72                             warn "WTF? $content"; 
    73                         } 
    74                     }; 
    75                     warn $@ if $@; 
    76                 } 
    77             } 
    78             return; 
    79         } 
    80     ); 
    81     my $content = $doc->serialize; 
    82     $content =~ s/^__END__$//smg; 
    83     say "{\n$content\n}\n"; 
    84 } 
    85  
    86 say "1;"; 
     377                            replace_node($_[0], $_[1], $src); 
     378                        } 
     379                        push @attrs, $attr; 
     380                    } 
     381                }; 
     382                warn $@ if $@; 
     383            }, 
     384        ); 
     385        my $content = $doc->serialize; 
     386        $content =~ s/^__END__$//smg; 
     387        $content =~ s/__PACKAGE__->meta->make_immutable(\(\))?;/ 
     388            ';' . generate_constructor_method_inline($klass, \@attrs) . ';sub DESTRUCTOR { }' 
     389        /e; 
     390        say "{\n$content\n}\n"; 
     391    } 
     392 
     393    say "1;"; 
     394} 
    87395 
    88396__END__