has args => (is => 'ro', isa => ArrayRef, required => 1);
-has introduces_names => (is => 'ro', isa => HashRef, required => 1);
+has introduced_names => (is => 'ro', isa => HashRef, required => 1);
-has requires_names => (is => 'ro', isa => HashRef, required => 1);
+has required_names => (is => 'ro', isa => HashRef, required => 1);
sub resolve_for {
my ($self, $scope) = @_;
package DX::PropositionSequence;
-use Types::Standard qw(ArrayRef);
+use Types::Standard qw(ArrayRef HashRef);
use DX::Class;
has members => (is => 'ro', isa => ArrayRef[Proposition], required => 1);
+has external_names => (is => 'ro', isa => HashRef, required => 1);
+
+has internal_names => (is => 'ro', isa => HashRef, required => 1);
+
sub new_empty {
- shift->new(members => []);
+ shift->new(
+ members => [],
+ external_names => {},
+ internal_names => {},
+ );
}
-sub but_append_proposition {
+sub with_additional_proposition {
my ($self, $prop) = @_;
- $self->but(members => [ @{$self->members}, $prop ]);
+ my %already_names = (
+ %{$self->external_names}, %{$self->internal_names}
+ );
+ my @fail;
+ if (
+ my @missing = grep !$already_names{$_}, sort keys %{$prop->required_names}
+ ) {
+ push @fail,
+ " variables ".join(' ', @missing)." required but not in scope";
+ }
+ if (
+ my @shadow = grep $already_names{$_}, keys %{$prop->introduced_names}
+ ) {
+ push @fail,
+ " new variables ".join(' ', @shadow)." are already in scope";
+ }
+ if (@fail) {
+ die join("\n", "Can't add call to ${\$prop->predicate}:", @fail, '');
+ }
+ $self->but(
+ members => [ @{$self->members}, $prop ],
+ internal_names => { %{$self->internal_names}, %{$prop->introduced_names} },
+ );
}
1;
sub new_search_state_for {
my ($self, $prop_seq) = @_;
- my @local_names = map { keys %{$_->introduces_names} }
+ my @local_names = map { keys %{$_->introduced_names} }
@{$prop_seq->members};
my $scope = DX::Scope->new(
predicates => $self->predicates,
sub with_additional_proposition {
my ($self, $prop) = @_;
my $prop_seq = $self->proposition_sequence
- ->but_append_proposition($prop);
+ ->with_additional_proposition($prop);
my $sol_ss = $self->new_search_state_for($prop_seq)
->find_solution;
die "No solution" unless $sol_ss;
my $prop = DX::Proposition->new(
predicate => $pred,
args => \@args,
- introduces_names => $intro,
- requires_names => $need,
+ introduced_names => $intro,
+ required_names => $need,
);
my $old_qstate = $self->shell_state->current_query_state;
my $qstate = $old_qstate->with_additional_proposition($prop);