#!/usr/bin/perl
package Blondie::Reducer::DynamicScoping;
use strict;
use warnings;
{
use Blondie::ADTs;
package Blondie::Reducer::DynamicScoping::Pad;
use base qw/Blondie::Map/;
}
sub find_dyn_sym {
my $self = shift;
my $symbol = shift;
foreach my $pad ($self->pads) {
return $pad if $pad->name eq $symbol;
}
die "symbol $symbol could not be resolved by $self";
}
sub find_immediate_dyn_sym {
my $self = shift;
my $symbol = shift;
foreach my $pad (@{ ($self->scopes)[0] }) {
return $pad if $pad->name eq $symbol;
}
die "symbol $symbol could not be resolved in the last scope by $self. It may be defined in an upper scope";
}
sub new_pad {
my $self = shift;
my $name = shift;
my $val = shift;
my $pad = Blondie::Reducer::DynamicScoping::Pad->new(
name => $name,
val => $val,
);
push @{ $self->{scopes}[0] }, $pad;
}
sub pads {
my $self = shift;
map { @$_ } $self->scopes;
}
sub scopes {
my $self = shift;
@{ $self->{scopes} }
}
sub enter_scope {
my $self = shift;
unshift @{ $self->{scopes} }, [];
}
sub leave_scope {
my $self = shift;
shift @{ $self->{scopes} };
}
__PACKAGE__;
__END__
=pod
=head1 NAME
Blondie::Reducer::DynamicScoping - a base class (probably a role) for
implementing dynamic scopes (not really a reduer).
=head1 SYNOPSIS
use base qw/Blondie::Reducer::DynamicScoping/;
...
$self->enter_scope; # opens a new scope
$self->new_pad("name" => $value); # shadows any previous "name"
$self->find_dyn_sym("name"); # returns $value
$self->leave_scope; # deletes pads since last enter_scope
=head1 DESCRIPTION
Assumes a hash structure of $self, and uses the 'scopes' keys therein.
=cut