While reading through actions.pm I found that method scope_declarator
wasn't very readable because it was very long.
A big part of that is the declaration of attributes which needs some
special handling.
The attached patch moves that code to a separate function called
declare_attribute. It doesn't change any semantics.
Cheers,
Moritz
--
Moritz Lenz
http://moritz.faui2k3.org/ | http://perl-6.de/
Index: languages/perl6/src/parser/actions.pm
===================================================================
--- languages/perl6/src/parser/actions.pm (revision 27393)
+++ languages/perl6/src/parser/actions.pm (working copy)
@@ -1228,7 +1228,98 @@
make $past;
}
+sub declare_attribute($/) {
+ # Get the
+ # class or role we're in.
+ our $?CLASS;
+ our $?ROLE;
+ our $?PACKAGE;
+ our $?BLOCK;
+ my $class_def;
+ if $?ROLE =:= $?PACKAGE {
+ $class_def := $?ROLE;
+ }
+ else {
+ $class_def := $?CLASS;
+ }
+ unless defined( $class_def ) {
+ $/.panic(
+ "attempt to define attribute '"
+ ~ $name ~ "' outside of class"
+ );
+ }
+ # Add attribute to class (always name it with ! twigil).
+ my $variable := $<scoped><variable_decl><variable>;
+ my $name := ~$variable<sigil> ~ '!' ~ ~$variable<name>;
+ $class_def.push(
+ PAST::Op.new(
+ :pasttype('callmethod'),
+ :name('!keyword_has'),
+ PAST::Var.new(
+ :name('Perl6Object'),
+ :scope('package')
+ ),
+ PAST::Var.new(
+ :name('$def'),
+ :scope('lexical')
+ ),
+ PAST::Val.new( :value($name) )
+ )
+ );
+
+ # If we have no twigil, make $name as an alias to $!name.
+ if $variable<twigil>[0] eq '' {
+ $?BLOCK.symbol(
+ ~$variable<sigil> ~ ~$variable<name>, :scope('attribute')
+ );
+ }
+
+ # If we have a . twigil, we need to generate an accessor.
+ elsif $variable<twigil>[0] eq '.' {
+ my $accessor := PAST::Block.new(
+ PAST::Stmts.new(
+ PAST::Var.new( :name($name), :scope('attribute') )
+ ),
+ :name(~$variable<name>),
+ :blocktype('declaration'),
+ :pirflags(':method'),
+ :node( $/ )
+ );
+ $?CLASS.unshift($accessor);
+ }
+
+ # If it's a ! twigil, we're done; otherwise, error.
+ elsif $variable<twigil>[0] ne '!' {
+ $/.panic(
+ "invalid twigil "
+ ~ $variable<twigil>[0] ~ " in attribute declaration"
+ );
+ }
+
+ # Is there any "handles" trait verb?
+ if $<scoped><variable_decl><trait> {
+ for $<scoped><variable_decl><trait> {
+ if $_<trait_verb><sym> eq 'handles' {
+ # Get the methods for the handles and add them to
+ # the class
+ my $meths := process_handles(
+ $/,
+ $( $_<trait_verb><EXPR> ),
+ $name
+ );
+ for @($meths) {
+ $class_def.push($_);
+ }
+ }
+ }
+ }
+
+ # Register the attribute in the scope.
+ $?BLOCK.symbol($name, :scope('attribute'));
+
+}
+
method scope_declarator($/) {
my $past;
our $?BLOCK;
@@ -1238,94 +1329,9 @@
if $<scoped><variable_decl> {
# Variable. Now go by declarator.
if $declarator eq 'has' {
- # Has declarations are attributes and need special handling. Get the
- # class or role we're in.
- our $?CLASS;
- our $?ROLE;
- our $?PACKAGE;
- my $class_def;
- if $?ROLE =:= $?PACKAGE {
- $class_def := $?ROLE;
- }
- else {
- $class_def := $?CLASS;
- }
- unless defined( $class_def ) {
- $/.panic(
- "attempt to define attribute '"
- ~ $name ~ "' outside of class"
- );
- }
+ # Has declarations are attributes and need special handling.
+ declare_attribute($/);
- # Add attribute to class (always name it with ! twigil).
- my $variable := $<scoped><variable_decl><variable>;
- my $name := ~$variable<sigil> ~ '!' ~ ~$variable<name>;
- $class_def.push(
- PAST::Op.new(
- :pasttype('callmethod'),
- :name('!keyword_has'),
- PAST::Var.new(
- :name('Perl6Object'),
- :scope('package')
- ),
- PAST::Var.new(
- :name('$def'),
- :scope('lexical')
- ),
- PAST::Val.new( :value($name) )
- )
- );
-
- # If we have no twigil, make $name as an alias to $!name.
- if $variable<twigil>[0] eq '' {
- $?BLOCK.symbol(
- ~$variable<sigil> ~ ~$variable<name>, :scope('attribute')
- );
- }
-
- # If we have a . twigil, we need to generate an accessor.
- elsif $variable<twigil>[0] eq '.' {
- my $accessor := PAST::Block.new(
- PAST::Stmts.new(
- PAST::Var.new( :name($name), :scope('attribute') )
- ),
- :name(~$variable<name>),
- :blocktype('declaration'),
- :pirflags(':method'),
- :node( $/ )
- );
- $?CLASS.unshift($accessor);
- }
-
- # If it's a ! twigil, we're done; otherwise, error.
- elsif $variable<twigil>[0] ne '!' {
- $/.panic(
- "invalid twigil "
- ~ $variable<twigil>[0] ~ " in attribute declaration"
- );
- }
-
- # Is there any "handles" trait verb?
- if $<scoped><variable_decl><trait> {
- for $<scoped><variable_decl><trait> {
- if $_<trait_verb><sym> eq 'handles' {
- # Get the methods for the handles and add them to
- # the class
- my $meths := process_handles(
- $/,
- $( $_<trait_verb><EXPR> ),
- $name
- );
- for @($meths) {
- $class_def.push($_);
- }
- }
- }
- }
-
- # Register the attribute in the scope.
- $?BLOCK.symbol($name, :scope('attribute'));
-
# We don't want to generate any PAST at the point of the declaration.
$past := PAST::Stmts.new();
}