Treex-PML

 view release on metacpan or  search on metacpan

lib/Treex/PML/Schema/Derive.pm  view on Meta::CPAN

    if ($type->{structure}) {
      my $derive_structure = $derive->{structure};
      my $target_structure = $type->{structure};
      foreach my $attr (qw(role name)) {
	if (exists $derive_structure->{$attr}) {
	  $target_structure->{$attr} = $derive_structure->{$attr};
	  push @{$target_structure->{-attributes}},$attr
	    unless grep { $_ eq $attr } @{$target_structure->{-attributes}};
	}
      }
      $target_structure->{member} ||= {};
      my $members = $target_structure->{member};
      while (my ($member,$value) = each %{$derive_structure->{member}}) {
	$members->{$member} = $target_structure->copy_decl($value); # FIXME: no need if we remove derives in the end
      }
      if (ref $derive_structure->{delete}) {
	for my $member (@{$derive_structure->{delete}}) {
	  delete $members->{$member};
	}
      }
    } else {

      croak "Cannot derive structure type '$name' from a non-structure '$source'\n";
    }
  } elsif ($derive->{sequence}) {
    if ($type->{sequence}) {
      my $derive_sequence = $derive->{sequence};
      my $target_sequence = $type->{sequence};
      if (exists $derive_sequence->{role}) {
	$target_sequence->{role} = $derive_sequence->{role};
	push @{$target_sequence->{-attributes}},'role'
	  unless grep { $_ eq 'role' } @{$target_sequence->{-attributes}};
      }
      if (exists $derive_sequence->{content_pattern}) {
        $target_sequence->{content_pattern} = $derive_sequence->{content_pattern};
        push @{$target_sequence->{-attributes}},'content_pattern'
	  unless grep { $_ eq 'content_pattern' } @{$target_sequence->{-attributes}};
      }
      $target_sequence->{element} ||= {};
      my $elements = $target_sequence->{element};
      while (my ($element,$value) = each %{$derive_sequence->{element}}) {
	$elements->{$element} = $target_sequence->copy_decl($value); # FIXME: no need if we remove derives in the end
      }
      if (ref $derive_sequence->{delete}) {
	for my $element (@{$derive_sequence->{delete}}) {
	  delete $elements->{$element};
	}
      }
    } else {
      require Data::Dumper;
#      print STDERR Data::Dumper::Dumper([$type]);
      croak "Cannot derive sequence type '$name' from a non-sequence '$source'\n";
    }
  } elsif ($derive->{container}) {
    if ($type->{container}) {
      my $derive_container = $derive->{container};
      my $target_container = $type->{container};
      for my $attr (qw(type role)) {
	next unless exists $derive_container->{$attr};
	if ($attr eq 'type' and !exists($target_container->{type})) {
	  foreach my $d (qw(list alt structure container sequence cdata)) {
	    if (exists $target_container->{$d}) {
	      delete $target_container->{$d};
	      last;
	    }
	  }
	  delete $target_container->{-decl};
	  delete $target_container->{-resolved};
	}
	$target_container->{$attr} = $derive_container->{$attr};
	push @{$target_container->{-attributes}},$attr
	  unless grep { $_ eq $attr } @{$target_container->{-attributes}};
      }
      $target_container->{attribute} ||= {};
      my $attributes = $target_container->{attribute};
      while (my ($attribute,$value) = each %{$derive_container->{attribute}}) {
	$attributes->{$attribute} = $target_container->copy_decl($value); # FIXME: no need if we remove derives in the end
      }
      if (ref $derive_container->{delete}) {
	for my $attribute (@{$derive_container->{delete}}) {
	  delete $attributes->{$attribute};
	}
      }
    } else {
      croak "Cannot derive a container '$name' from a different type '$source'\n";
    }
  } elsif ($derive->{choice}) {
    my $choice = $derive->{choice};
    if ($type->{choice}) {
      my (@add,%delete);
      if (UNIVERSAL::isa($choice,'HASH')) {
	@add = @{$choice->{values}} if ref $choice->{values};
	@delete{ @{$choice->{delete}} }=() if ref $choice->{delete};
      } else {
	@add = @$choice;
      }
      my %seen;
      @{$type->{choice}{values}} =
	grep { !($seen{$_}++) and ! exists $delete{$_} } (@{$type->{choice}{values}},@add);
    } else {
      croak "Cannot derive a choice type '$name' from a non-choice type '$source'\n";
    }
  } else {
    unless ($name ne $source) {
      croak "<derive type='$source'> has no effect in $schema->{URL}\n";
    }
  }
}

1;
__END__

=head1 NAME

Treex::PML::Schema::Derive - a class representing derive instructions in a Treex::PML::Schema

=head1 DESCRIPTION

This is an auxiliary class  representing derive instructions in a L<Treex::PML::Schema>.
Note that all derive instructions are removed from the schema during parsing.



( run in 0.409 second using v1.01-cache-2.11-cpan-524268b4103 )