pervasive type constraints
[scpubgit/DX.git] / lib / DX / Scope.pm
1 package DX::Scope;
2
3 use DX::Class;
4
5 has predicates => (is => 'ro', isa => HashRef[Predicate], required => 1);
6
7 has globals => (is => 'ro', isa => DictValue, required => 1);
8
9 has locals => (is => 'ro', isa => ArrayRef[DictValue], required => 1);
10
11 has lex_map => (is => 'ro', isa => HashRef[ArrayRef[Str]], required => 1);
12
13 #has known_facts => (is => 'ro', required => 1);
14
15 sub lookup_predicate {
16   my ($self, $predicate) = @_;
17   return $self->predicates->{$predicate} || die "No such predicate: $predicate";
18 }
19
20 sub lookup {
21   my ($self, $symbol) = @_;
22   if ($symbol =~ /^[_A-Z]/) {
23     my @mapped = @{$self->lex_map->{$symbol}||[]}
24       or die "No such name in scope: $symbol";
25     my $targ = $self;
26     $targ = $targ->get_member_at($_) for @mapped;
27     return $targ;
28   }
29   return $self->globals->get_member_at($symbol)
30    || die "No such name in scope: $symbol";
31 }
32
33 sub depth { $#{$_[0]->locals} }
34
35 sub prune_to {
36   my ($self, $to) = @_;
37   $self->but(locals => [ @{$self->locals}[0..$to] ]);
38 }
39
40 sub get_member_at {
41   my ($self, $at) = @_;
42   if ($at =~ /^[0-9]+$/) {
43     return $self->locals->[$at];
44   }
45   return $self->globals->get_member_at($at);
46 }
47
48 sub with_member_at {
49   my ($self, $at, $value) = @_;
50   if ($at =~ /^[0-9]+$/) {
51     my @locals = @{$self->locals};
52     $locals[$at] = $value;
53     return $self->but(
54       locals => \@locals
55     );
56   }
57   return $self->but(
58     globals => $self->globals->with_member_at($at, $value)
59   );
60 }
61
62 sub apply_updates {
63   my ($self, @updates) = @_;
64   my @events;
65   my $scope = $self;
66   ($scope, @events) = ($_->apply_to($scope), @events) for @updates;
67   return ($scope, @events);
68 }
69
70 1;