File Coverage

blib/lib/MooseX/Compile/Compiler.pm
Criterion Covered Total %
statement 3 3 100.0
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 4 4 100.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package MooseX::Compile::Compiler;
4 2     2   29361 use base qw(MooseX::Compile::Base);
  2         5  
  2         848  
5              
6             use strict;
7             use warnings;
8              
9             use Data::Dump qw(dump);
10             use Data::Visitor::Callback;
11             use Storable;
12             use B;
13             use B::Deparse;
14             use PadWalker;
15             use Class::Inspector;
16              
17             our %compiled_classes;
18              
19             use constant DEBUG => MooseX::Compile::Base::DEBUG();
20              
21             # FIXME make this Moose based eventually
22             sub new {
23             my ( $class, %args ) = @_;
24             bless \%args, $class;
25             }
26              
27             sub compile_class {
28             my ( $self, %args ) = @_;
29             my $class = $args{class};
30              
31             ( my $short_name = "$class.pm" ) =~ s{::}{/}g;
32             $args{short_name} = $short_name;
33              
34             unless ( defined $args{file} ) {
35             $args{file} = $INC{$short_name};
36             }
37              
38             unless ( defined $args{pmc_file} ) {
39             $args{pmc_file} = "$args{file}c";
40             }
41              
42             if ( $compiled_classes{$class}++ ) {
43             warn "already compiled class '$class'\n" if DEBUG;
44             return;
45             }
46              
47             my $t = times;
48              
49             $self->cache_meta(%args);
50             $self->write_pmc_file(%args);
51              
52             warn "compilation of .pmc and .mopc for class '$class' took " . ( times - $t ) . "s\n" if DEBUG;
53             }
54              
55             # FIXME these should really be methods, I suppose
56              
57             sub sym ($$;@) {
58             my ( $sym, $type, @args ) = @_;
59             bless { @args, name => $sym }, "MooseX::Compile::mangled::$type";
60             }
61              
62             sub package_name ($;$) {
63             my ( $code, $cv ) = @_;
64             $cv ||= B::svref_2object($code);
65             local $@;
66             return eval { $cv->GV->STASH->NAME };
67             }
68              
69             sub code_name ($;$) {
70             my ( $code, $cv ) = @_;
71             $cv ||= B::svref_2object($code);
72             local $@;
73             return eval { join("::", package_name($code, $cv), $cv->GV->NAME) };
74             }
75              
76             sub verified_code_name ($;$) {
77             my ( $code, $cv ) = @_;
78              
79             if ( my $name = code_name($code, $cv) ) {
80             if ( verify_code_name($code, $name) ) {
81             return $name;
82             }
83             }
84              
85             return;
86             }
87              
88             sub verify_code_name ($$) {
89             my ( $code, $name ) = @_;
90              
91             no strict 'refs';
92             \&$name == $code;
93             }
94              
95             sub subref ($;$) {
96             my ( $code, $name ) = @_;
97              
98             if ( ref $code ) {
99             my $cv = B::svref_2object($code);
100             $name ||= code_name($code, $cv);
101             if ( $name && verify_code_name($code,$name) ) {
102             my @args;
103             if ( -f ( my $file = $cv->FILE ) ) {
104             my %rev_inc = reverse %INC;
105             push @args, file => $rev_inc{$file} if $rev_inc{$file} !~ /^(?:Moose|metaclass)\.pm$/;
106             }
107             return sym( $name, "subref", @args );
108             } else {
109             warn "$code has name '$name', but it doesn't point back to the cv" if $name;
110             require Data::Dumper;
111             no strict 'refs';
112             local $Data::Dumper::Deparse = 1;
113             warn Data::Dumper::Dumper({
114             name => $name,
115             name_strval => ("". \&$name),
116             name_ref => \&$name,
117             arg_ref => $code,
118             arg_strval => "$code",
119             });
120             die "Can't make a symbolic ref to $code, it has no name or the name is invalid";
121             }
122             } else {
123             return sym($code, "subref");
124             }
125             }
126              
127             sub create_visitor {
128             my ( $self, %args ) = @_;
129             my $class = $args{class};
130              
131             Data::Visitor::Callback->new(
132             "object" => sub {
133             my ( $self, $obj ) = @_;
134              
135             return $obj if $obj->isa("Moose::Meta::TypeConstraint");
136              
137             $self->visit_ref($obj);
138             },
139             object_final => sub {
140             my ( $self, $obj ) = @_;
141              
142             if ( ref($obj) =~ /^Class::MOP::Class::__ANON__::/x ) {
143             die "Instance of anonymous class cannot be thawed: $obj";
144             }
145              
146             return $obj;
147             },
148             "Class::MOP::Class" => sub {
149             my ( $self, $meta ) = @_;
150              
151             if ( $meta->is_immutable ) {
152             my $options = $meta->immutable_transformer->options;
153             bless( $meta, $meta->{___original_class} ), # it's a copy, we can rebless
154             return bless {
155             class => $meta,
156             options => $options,
157             }, "MooseX::Compile::mangled::immutable_metaclass";
158             }
159            
160             if ( $meta->is_anon_class ){
161             warn "Can't reliably store anonymouse metaclasses yet";
162             }
163              
164             return $meta;
165             },
166             "Moose::Meta::TypeConstraint" => sub {
167             my ( $self, $constraint ) = @_;
168              
169             if ( defined ( my $name = $constraint->name ) ) {
170             return sym $name, "constraint";
171             } else {
172             warn "Anonymous constraint $constraint left in metaclass";
173             return $constraint;
174             }
175             },
176             code => sub {
177             my ( $self, $code ) = @_;
178              
179             if ( my $subname = code_name($code) ) {
180             if ( $subname =~ /^Moose::Meta::Method::\w+::(.*)$/ ) {
181             # FIXME should this be verified more closely?
182             # sometimes the coderef $code doesn't match \&{ $class::$1 }
183             return subref "${class}::$1";
184             } elsif ( $subname =~ /^(?:Moose|metaclass)::([^:]+)$/ ) {
185             my $method = $1;
186              
187             if ( $method eq 'meta' ) {
188             return subref "${class}::meta";
189             } else {
190             die "subname: $subname";
191             }
192             } elsif ( $subname !~ /__ANON__$/ ) {
193             return subref $code, $subname;
194             } else {
195             warn "Unable to locate symbol for $code ($subname) found in $class";
196             use B::Deparse;
197             warn B::Deparse->new->coderef2text($code);
198             return $code;
199             }
200             }
201              
202             return $code;
203             },
204             );
205             }
206              
207             sub deflate_meta {
208             my ( $self, %args ) = @_;
209             my $meta = $args{meta};
210            
211             my $visitor = $self->create_visitor(%args);
212            
213             $visitor->visit($meta);
214             }
215              
216             sub cache_meta {
217             my ( $self, %args ) = @_;
218             my $class = $args{class};
219              
220             my $meta = $self->deflate_meta( %args, meta => $class->meta );
221             $self->store_meta( %args, meta => $meta );
222             }
223              
224             sub store_meta {
225             my ( $self, %args ) = @_;
226             my $meta = $args{meta};
227              
228             my $mopc_file = $self->cached_meta_file(%args);
229             $mopc_file->dir->mkpath;
230              
231             local $@;
232             eval { Storable::nstore( $meta, $mopc_file ) };
233              
234             if ( $@ ) {
235             require YAML;
236             no warnings 'once';
237             $YAML::UseCode = 1;
238             die join("\n", $@, YAML::Dump($meta) );
239             }
240            
241             if ( DEBUG ) {
242             warn "stored $meta in '$mopc_file'\n";
243             }
244              
245             return 1;
246             }
247              
248             sub method_category_filters {
249             my ( $self, %args ) = @_;
250              
251             return (
252             # FIXME recognize aliased methods
253             sub {
254             my ( $self, $entry ) = @_;
255             no warnings 'uninitialized';
256             return "meta" if $entry->{name} eq 'meta' and package_name($entry->{body}) =~ /^(?: Moose | metaclass )/x,
257             },
258             sub {
259             my ( $self, $entry ) = @_;
260             return "generated" if $entry->{meta}->isa("Class::MOP::Method::Generated");
261             },
262             sub {
263             my ( $self, $entry ) = @_;
264             return "file" if B::svref_2object($entry->{body})->FILE eq $args{file};
265             },
266             sub { "unknown_methods" },
267             );
268             }
269              
270             sub function_category_filters {
271             my ( $self, %args ) = @_;
272            
273             return (
274             # FIXME check for Moose exports, too (Scalar::Util stuff, etc)
275             sub {
276             my ( $self, $entry ) = @_;
277             no warnings 'uninitialized';
278             return "moose_sugar" if package_name($entry->{body}) eq 'Moose';
279             },
280             sub { "unknown_functions" },
281             );
282             }
283              
284             sub extract_code_symbols {
285             my ( $self, %args ) = @_;
286             my $class = $args{class};
287              
288             my %seen;
289             my %categorized_symbols;
290              
291             {
292             my @method_filters = $self->method_category_filters(%args);
293             my $method_map = $class->meta->get_method_map;
294              
295             foreach my $name ( sort keys %$method_map ) {
296             $seen{$name}++;
297              
298             my $method = $method_map->{$name};
299             my $body = $method->body;
300              
301             my $entry = { name => $name, meta => $method, body => $body };
302              
303             foreach my $filter ( @method_filters ) {
304             if ( my $category = $self->$filter($entry) ) {
305             push @{ $categorized_symbols{$category} ||= [] }, $entry;
306             last;
307             }
308             }
309             }
310             }
311              
312             {
313             my %symbols; @symbols{@{ Class::Inspector->functions($class) || [] }} = @{ Class::Inspector->function_refs($class) || [] };
314              
315             my @function_filters = $self->function_category_filters(%args);
316              
317             foreach my $name ( sort grep { not $seen{$_}++ } keys %symbols ) {
318             my $body = $symbols{$name};
319             my $entry = { name => $name, body => $body };
320              
321             foreach my $filter ( @function_filters ) {
322             if ( my $category = $self->$filter($entry) ) {
323             push @{ $categorized_symbols{$category} ||= [] }, $entry;
324             last;
325             }
326             }
327             }
328             }
329              
330             return %categorized_symbols;
331             }
332              
333             sub compile_code_symbols {
334             my ( $self, %args ) = @_;
335              
336             my $symbols = $args{all_symbols};
337              
338             my @ret;
339              
340             foreach my $category ( @{ $args{'symbol_categories'} } ) {
341             my $method = "compile_${category}_code_symbols";
342             push @ret, $self->$method( %args, symbols => delete($symbols->{$category}) );
343             }
344              
345             @ret;
346             }
347              
348             sub compile_file_code_symbols {
349             # this is already taken care of by the inclusion of the whole .pm after the preamble
350             return;
351             }
352              
353             sub compile_meta_code_symbols {
354             # we fake this one
355             return;
356             }
357              
358             sub compile_moose_exports_code_symbols {
359             # not yet implemented
360             return;
361             }
362              
363             sub compile_moose_sugar_code_symbols {
364             my ( $self, %args ) = @_;
365             return map {
366             my $name = $_->{name};
367             my $proto = prototype($_->{body});
368             $proto = $proto ? " ($proto)" : "";
369             "*$name = Sub::Name::subname('Moose::$name', sub$proto { });";
370             } @{ $args{symbols} || [] };
371             }
372              
373              
374             sub compile_generated_code_symbols {
375             my ( $self, %args ) = @_;
376             map { sprintf "*%s = %s;", $_->name => $self->compile_method(%args, method => $_) } map { $_->{meta} } @{ $args{symbols} };
377             }
378              
379             sub compile_aliased_code_symbols {
380             return;
381             }
382              
383             sub compile_unknown_method_code_symbols {
384             return;
385             }
386              
387             sub compile_unknown_function_code_symbols {
388             return;
389             }
390              
391             sub compile_method {
392             my ( $self, %args ) = @_;
393             my ( $class, $method ) = @args{qw(class method)};
394              
395             my $d = B::Deparse->new;
396              
397             my $body = $method->body;
398              
399             my $body_str = $d->coderef2text($body);
400              
401             my $closure_vars = PadWalker::closed_over($body);
402              
403             my @env;
404              
405             if ( my $constraints = delete $closure_vars->{'@type_constraints'} ) {
406             my @constraint_code = map {
407             my $name = $_->name;
408              
409             defined $name
410             ? "Moose::Util::TypeConstraints::find_type_constraint(". dump($name) .")"
411             : "die 'missing constraint'"
412             } @$constraints;
413            
414             push @env, "CORE::require Moose::Util::TypeConstraints::OptimizedConstraints", join("\n ", 'my @type_constraints = (', map { "$_," } @constraint_code ) . "\n)",
415             }
416            
417             push @env, map {
418             my $ref = $closure_vars->{$_};
419              
420             my $scalar = ref($ref) eq 'SCALAR' || ref($ref) eq 'REF';
421              
422             "my $_ = " . ( $scalar
423             ? $self->_value_to_perl($$ref)
424             : "(" . join(", ", map { $self->_value_to_perl($_) } @$ref ) . ")" )
425             } keys %$closure_vars;
426              
427             my $name = code_name($body);
428             my $quoted_name = dump($name);
429              
430             if ( @env ) {
431             my $env = join(";\n\n", @env);
432             $env =~ s/^/ /gm;
433             return "Sub::Name::subname( $quoted_name, do {\n$env;\n\n\nsub $body_str\n})";
434             } else {
435             return "Sub::Name::subname( $quoted_name, sub $body_str )";
436             }
437             }
438              
439             sub _value_to_perl {
440             my ( $self, $value ) = @_;
441              
442             ( (ref($value)||'') eq 'CODE'
443             ? $self->_subref_to_perl($value)
444             : Data::Dump::dump($value) )
445             }
446              
447             sub _subref_to_perl {
448             my ( $self, $subref ) = @_;
449              
450             my %rev_inc = reverse %INC;
451              
452             if ( ( my $name = code_name($subref) ) !~ /__ANON__$/ ) {
453             if ( -f ( my $file = B::svref_2object($subref)->FILE ) ) {
454             return "do { require " . dump($rev_inc{$file}) . "; \\&$name }";
455             } else {
456             return '\&' . $name;
457             }
458             } else {
459             "sub " . B::Deparse->new->coderef2text($subref);
460             }
461             }
462              
463             sub write_pmc_file {
464             my ( $self, %args ) = @_;
465              
466             my ( $class, $short_name, $file, $pmc_file ) = @args{qw(class short_name file pmc_file)};
467              
468             $pmc_file->dir->mkpath;
469              
470             open my $pm_fh, "<", $file or die "open($file): $!";
471             open my $pmc_fh, ">", "$pmc_file" or die "Can't write .pmc, open($pmc_file): $!";
472              
473             local $/;
474              
475             my $pm = <$pm_fh>;
476              
477             close $pm_fh;
478              
479             print $pmc_fh "$1\n\n" if $pm =~ /^(\#\!.*)/; # copy shebang
480              
481             print $pmc_fh $self->pmc_preamble( %args ), "\n";
482              
483             print $pmc_fh "# verbatim copy of $file follows\n";
484             print $pmc_fh "# line 1\n";
485              
486             print $pmc_fh $pm;
487              
488             close $pmc_fh or die "Can't write .pmc, close($pmc_file): $!";
489              
490             warn "wrote PMC file '$pmc_file'\n" if DEBUG;
491             }
492              
493             sub pmc_preamble_comment {
494             my ( $self, %args ) = @_;
495              
496             return <<COMMENT;
497             # This file is generated by MooseX::Compile, and contains a cached
498             # version of the class '$args{class}'.
499             COMMENT
500             }
501              
502             sub pmc_preamble_header {
503             my( $self, %args ) = @_;
504             my $class = $args{class};
505              
506             return join("\n\n\n", map { my $method = "pmc_preamble_header_$_"; $self->$method(%args) } $self->pmc_preamble_header_pieces(%args) );
507             }
508              
509             sub pmc_preamble_header_pieces {
510             return qw(timing modules register_pmc hide_moose);
511             }
512              
513             sub pmc_preamble_header_timing {
514             return <<'TIMING';
515             # used in debugging output if any
516             my $__mx_compile_t; BEGIN { $__mx_compile_t = times }
517             TIMING
518             }
519              
520             sub pmc_preamble_header_modules {
521             return <<'MODULES'
522             # load a few modules we need
523             use Sub::Name ();
524             use Scalar::Util ();
525             MODULES
526             }
527              
528             sub pmc_preamble_header_register_pmc {
529             my ( $self, %args ) = @_;
530             my ( $quoted_class, $version ) = @args{qw(quoted_class quoted_compiler_version)};
531              
532             return <<REGISTER;
533             # Register this file as a PMC
534             use MooseX::Compile::Bootstrap (
535             class => $quoted_class,
536             file => __FILE__,
537             version => $version,
538             );
539             REGISTER
540             }
541              
542             sub pmc_preamble_header_hide_moose {
543             my ( $self, %args ) = @_;
544              
545             my $hide = <<'#\'HIDE_MOOSE';
546             #\
547             # disable requiring and importing of Moose from this compile class
548             my ( $__mx_compile_prev_require, %__mx_compile_overridden_imports );
549              
550             BEGIN {
551             $__mx_compile_prev_require = defined &CORE::GLOBAL::require ? \&CORE::GLOBAL::require : undef;
552              
553             no warnings 'redefine';
554              
555             # FIXME move this to Bootstrap? Bootstrap->override_global_require( class => $$quoted_class$$ )?
556             *CORE::GLOBAL::require = sub {
557             my ( $faked_class ) = ( $_[0] =~ m/^ ( Moose | metaclass ) \.pm $/x );
558              
559             return 1 if caller() eq $$quoted_class$$ and $faked_class;
560              
561             my $hook;
562              
563             if ( $faked_class and not $INC{$_[0]} ) {
564             # load Moose or metaclass in a clean env, and then wrap it's import()
565             no strict 'refs';
566              
567             my $import = "${faked_class}::import";
568              
569             my $wrapper = \&$import;
570              
571             undef *$import; # clean out the symbol so it doesn't warn about redefining
572              
573             $hook = bless [sub {
574             $__mx_compile_overridden_imports{$faked_class} = \&$import; # stash the real import
575             *$import = $wrapper;
576             }], "MooseX::Compile::Scope::Guard";
577             }
578              
579             if ( $__mx_compile_prev_require ) {
580             &$__mx_compile_prev_require;
581             } else {
582             require $_[0];
583             }
584             };
585              
586             foreach my $class qw(Moose metaclass) {
587             no strict 'refs';
588              
589             my $import = "${class}::import";
590              
591             $__mx_compile_overridden_imports{$class} = defined &$import && \&$import;
592              
593             *$import = sub {
594             if ( caller eq $$quoted_class$$ ) {
595             if ( $class eq 'Moose' ) {
596             strict->import;
597             warnings->import;
598             }
599              
600             return;
601             }
602              
603             if ( my $sub = $__mx_compile_overridden_imports{\$class} ) {
604             goto $sub;
605             }
606              
607             return;
608             };
609             }
610             }
611             #'HIDE_MOOSE
612              
613             $hide =~ s/\$\$(\w+)\$\$/$args{$1}/ge;
614              
615             return $hide;
616             }
617              
618             sub pmc_preamble_setup_env {
619             my ( $self, %args ) = @_;
620              
621             my $class = $args{class};
622              
623             my $quoted_class = dump($class);
624              
625             my $decl = $self->pmc_preamble_class_def_for_begin(%args);
626              
627             return <<ENV;
628             # stub the sugar
629             BEGIN {
630             package $class;
631              
632             my \$fake_meta = bless { name => $quoted_class }, "MooseX::Compile::MetaBlackHole";
633             sub meta { \$fake_meta }
634              
635             $decl
636              
637             our \$__mx_is_compiled = 1;
638             }
639             ENV
640             }
641              
642             sub pmc_preamble_class_def_for_begin {
643             my ( $self, %args ) = @_;
644              
645             join("\n\n", $self->compile_code_symbols( %args, symbol_categories => [qw(moose_sugar moose_exports)] ) );
646             }
647              
648             sub pmc_preamble_at_end {
649             my ( $self, %args ) = @_;
650             my ( $class, $code ) = @args{qw(class code)};
651              
652             return <<HOOK
653             # try to approximate the time that Moose generated code enters the class
654             # this presumes you didn't stick the moose sugar in a BEGIN { } block
655             my \$__mx_compile_run_at_end = bless [ sub {
656              
657             $code
658              
659             } ], "MooseX::Compile::Scope::Guard";
660             HOOK
661             }
662              
663             sub pmc_preamble_unhide_moose {
664             my ( $self, %args ) = @_;
665              
666             return <<'#\'UNHIDE_MOOSE';
667             #\
668             # un-hijack CORE::GLOBAL::require so that it no longer hides Moose from this class
669             # and undo the import wrappers that likewise prevent importing if it's already loaded
670              
671             foreach my $class ( keys %__mx_compile_overridden_imports ) {
672             my $import = "${class}::import";
673             no strict 'refs';
674             if ( my $prev = delete $__mx_compile_overridden_imports{$class} ) {
675             no warnings 'redefine';
676             *$import = $prev;
677             } else {
678             delete ${ "${class}::" }{import};
679             }
680             }
681              
682             if ( $__mx_compile_prev_require ) {
683             no warnings 'redefine';
684             *CORE::GLOBAL::require = $__mx_compile_prev_require;
685             } else {
686             delete $CORE::GLOBAL::{require};
687             }
688             #'UNHIDE_MOOSE
689             }
690              
691             sub pmc_preamble_generated_code {
692             my ( $self, %args ) = @_;
693              
694             my $class = $args{class};
695              
696             return $self->pmc_preamble_at_end(
697             %args,
698             code => join("\n\n",
699             $self->pmc_preamble_unhide_moose(%args),
700             $self->pmc_preamble_generated_code_body(%args),
701             qq{warn "loading of class '$class' finished in " . (times - \$__mx_compile_t) . "s\\n" if MooseX::Compile::Base::DEBUG();},
702             ),
703             );
704             }
705              
706             sub pmc_preamble_generated_code_body {
707             my ( $self, %args ) = @_;
708              
709             my $class = $args{class};
710              
711             my $quoted_class = dump($class);
712              
713             return join("\n",
714             "package $class;",
715             $self->pmc_preamble_class_def_for_end(%args),
716             qq{warn "bootstrap of class '$class' finished in " . (times - \$__mx_compile_t) . "s\\n" if MooseX::Compile::Base::DEBUG();},
717             );
718             }
719              
720             sub pmc_preamble_class_def_for_end {
721             my ( $self, %args ) = @_;
722              
723             return (
724             $self->pmc_preamble_define_isa(%args),
725             $self->pmc_preamble_define_code_symbols(%args),
726             $self->pmc_preamble_call_post_hook(%args),
727             );
728             }
729              
730             sub pmc_preamble_define_isa {
731             my ( $self, %args ) = @_;
732              
733             my $ISA = dump($args{class}->meta->superclasses);
734              
735             return <<ISA
736             our \@ISA = $ISA;
737             MooseX::Compile::Bootstrap->load_classes(\@ISA);
738             ISA
739             }
740              
741             sub pmc_preamble_define_code_symbols {
742             my ( $self, %args ) = @_;
743              
744             return (
745             $self->compile_code_symbols(%args, symbol_categories => [qw(generated aliased)]),
746             $self->pmc_preamble_faked_code_symbols(%args),
747             );
748             }
749              
750             sub pmc_preamble_faked_code_symbols {
751             my ( $self, %args ) = @_;
752              
753             return <<METHODS
754             {
755             no warnings 'redefine';
756             *meta = Sub::Name::subname("Moose::meta", sub { MooseX::Compile::Bootstrap->load_cached_meta( class => __PACKAGE__, pmc_file => __FILE__ . 'c' ) });
757             }
758             METHODS
759             }
760              
761             sub pmc_preamble_call_post_hook {
762             my ( $self, %args ) = @_;
763             my $class = $args{class};
764              
765             return <<HOOK
766             ${class}::__mx_compile_post_hook()
767             if defined \&${class}::__mx_compile_post_hook;
768             HOOK
769             }
770              
771             sub pmc_preamble {
772             my ( $self, %args ) = @_;
773             my ( $class, $file ) = @args{qw(class file)};
774              
775             ( my $short_name = "$class.pm" ) =~ s{::}{/}g;
776              
777             $args{short_name} = $short_name;
778              
779             $args{quoted_class} = dump($class);
780              
781             $args{compiler_version} = $MooseX::Compile::Base::VERSION;
782              
783             $args{quoted_compiler_version} = dump($MooseX::Compile::Base::VERSION);
784              
785             $args{all_symbols} = { $self->extract_code_symbols(%args) };
786              
787             my $code = join("\n",
788             $self->pmc_preamble_comment(%args),
789             $self->pmc_preamble_header(%args),
790             $self->pmc_preamble_setup_env(%args),
791             $self->pmc_preamble_generated_code(%args),
792             $self->pmc_preamble_footer(%args),
793             );
794              
795             delete @{ $args{all_symbols} }{qw(file meta unknown_methods unknown_functions)};
796              
797             if ( DEBUG && keys %{ $args{all_symbols} } ) {
798             use Data::Dumper;
799             warn "leftover symbols: " . Dumper($args{all_symbols});
800             }
801              
802             return $code;
803             }
804              
805             sub pmc_preamble_footer {
806             my ( $self, %args ) = @_;
807             return <<FOOTER
808             BEGIN { warn "giving control back to original '$args{short_name}', bootstrap preamble took " . (times - \$__mx_compile_t) . "s\\n" if MooseX::Compile::Base::DEBUG() }
809             FOOTER
810             }
811              
812             __PACKAGE__
813              
814             __END__
815              
816             =pod
817              
818             =head1 NAME
819              
820             MooseX::Compile::Compiler - The Moose metaclass C<.pmc> compiler
821              
822             =head1 SYNOPSIS
823              
824             my $compiler = MooseX::Compile::Compiler->new();
825              
826             $compiler->compile_class(
827             class => "Foo::Bar",
828             file => $INC{"Foo/Bar.pm"},
829             pmc_file => "my/pmc/lib/Foo/Bar.pmc",
830             );
831              
832             =head1 DESCRIPTION
833              
834             This class does the heavy lifting of emitting a C<.pmc> and a C<.mopc> for a
835             given class.
836              
837             =head1 HERE BE DRAGONS
838              
839             This is alpha code. You can tinker, subclass etc but beware that things
840             definitely will change in the near future.
841              
842             When a final version comes out there will be a documented process for how to
843             extend the compiler to handle your classes, whether by subclassing or using
844             various hooks.
845              
846             =cut