package Lisp::Symbol;
use strict;
use vars qw(@EXPORT_OK %obarray $VERSION);

$VERSION = sprintf("%d.%02d", q$Revision: 1.6 $ =~ /(\d+)\.(\d+)/);

require Carp;
require Exporter;
*import = \&Exporter::import;
@EXPORT_OK = qw(symbol symbolp);

#use overload '""' => \&name;

%obarray = ();

my $t = symbol("t");
$t->value($t);

my $nil = symbol("nil");
$nil->value(undef);

sub symbol
{
    Lisp::Symbol->new(@_);
}

sub symbolp
{
    UNIVERSAL::isa($_[0], "Lisp::Symbol");
}

sub new
{
    my($class, $name) = @_;
    return $obarray{$name} if $obarray{$name};
    $obarray{$name} = bless {'name' => $name}, $class;
}

sub name
{
    $_[0]->{'name'};  # readonly
}

sub value
{
    my $self = shift;
    if (defined(wantarray) && !exists $self->{'value'}) {
	Carp::croak("Symbol's value as variable is void ($self->{'name'})");
    }
    my $old = $self->{'value'};
    $self->{'value'} = shift if @_;
    $old;
}

sub function
{
    my $self = shift;
    if (defined(wantarray) && !exists $self->{'function'}) {
	Carp::croak("Symbol's value as function is void ($self->{'name'})");
    }
    my $old = $self->{'function'};
    $self->{'function'} = shift if @_;
    $old;
}

sub plist
{
    my $self = shift;
    my $old = $self->{'plist'};
    $self->{'plist'} = shift if @_;
    $old;
}

sub get
{
    my $self = shift;
    $self->{'plist'}{$_[0]};
}

sub put
{
    my $self = shift;
    $self->{'plist'}{$_[0]} = $_[1];
}

sub dump_symbols
{
    print join("", map $obarray{$_}->as_string, sort keys %obarray);
}

sub as_string
{
    my $self = shift;
    require Lisp::Printer;
    my @str;
    push(@str, "$self->{'name'}\n");
    if (exists $self->{'value'}) {
	push(@str, "\tvalue: " .
	     Lisp::Printer::lisp_print($self->{'value'}) . "\n");
    }
    if (exists $self->{'function'}) {
	push(@str, "\tfunction: " .
	     Lisp::Printer::lisp_print($self->{'function'}) . "\n");
    }
    if (exists $self->{'plist'}) {
	push(@str, "\tplist: " .
	     Lisp::Printer::lisp_print($self->{'plist'}) . "\n");
    }
    join("", @str);
}

1;