3 use warnings FATAL
=> qw(all);
5 our @EXPORT_OK = qw(_sequential_Q _equal_Q _clone
6 $nil $true $false _nil_Q _true_Q _false_Q
7 _number_Q _symbol _symbol_Q _string_Q _keyword _keyword_Q _list_Q _vector_Q _sub_Q _function_Q
8 _hash_map _hash_map_Q _atom_Q);
9 use List::Util qw(pairs pairmap);
16 return _list_Q
($_[0]) || _vector_Q
($_[0])
21 my ($ota, $otb) = (ref $a, ref $b);
22 if (!(($ota eq $otb) || (_sequential_Q
($a) && _sequential_Q
($b)))) {
25 if ($a->isa('Mal::Symbol')) {
27 } elsif ($a->isa('Mal::Sequence')) {
28 if (! (scalar(@
$a) == scalar(@
$b))) {
31 for (my $i=0; $i<scalar(@
$a); $i++) {
32 if (! _equal_Q
($a->[$i], $b->[$i])) {
37 } elsif ($a->isa('Mal::HashMap')) {
38 if (! (scalar(keys %$a) == scalar(keys %$b))) {
41 foreach my $k (keys %$a) {
42 if (!_equal_Q
($a->{$k}, $b->{$k})) {
56 if ($obj->isa('Mal::CoreFunction')) {
57 return Mal
::FunctionRef
->new( $obj );
59 return bless {%{$obj}}, ref $obj;
66 package Mal
::BlankException
;
67 sub new
{ my $class = shift; bless Mal
::String
->new("Blank Line") => $class }
74 # Allow nil to be treated as an empty list or hash-map.
75 use overload
'@{}' => sub { [] }, '%{}' => sub { {} }, fallback
=> 1;
76 sub new
{ my $class = shift; my $s = 'nil'; bless \
$s => $class }
77 sub rest
{ Mal
::List
->new([]) }
81 sub new
{ my $class = shift; my $s = 'true'; bless \
$s => $class }
85 sub new
{ my $class = shift; my $s = 'false'; bless \
$s => $class }
88 our $nil = Mal
::Nil
->new();
89 our $true = Mal
::True
->new();
90 our $false = Mal
::False
->new();
92 sub _nil_Q
{ return $_[0] eq $nil }
93 sub _true_Q
{ return $_[0] eq $true }
94 sub _false_Q
{ return $_[0] eq $false }
99 sub new
{ my $class = shift; bless \
do { my $x=$_[0] }, $class }
101 sub _number_Q
{ $_[0]->isa('Mal::Integer') }
106 sub new
{ my $class = shift; bless \
do { my $x=$_[0] }, $class }
108 sub _symbol_Q
{ $_[0]->isa('Mal::Symbol') }
111 sub _string_Q
{ $_[0]->isa('Mal::String') && ${$_[0]} !~ /^\x{029e}/; }
114 sub _keyword
{ return Mal
::String
->new(("\x{029e}".$_[0])); }
115 sub _keyword_Q
{ $_[0]->isa('Mal::String') && ${$_[0]} =~ /^\x{029e}/; }
120 sub new
{ my $class = shift; bless \
$_[0] => $class }
127 package Mal
::Sequence
;
128 use overload
'@{}' => sub { $_[0]->{val
} }, fallback
=> 1;
129 sub new
{ my $class = shift; bless {'meta'=>$nil, 'val'=>$_[0]}, $class }
130 sub meta
{ $_[0]->{meta
} }
131 #sub _val { $_[0]->{val}->[$_[1]]->{val}; } # return value of nth item
132 sub rest
{ my @arr = @
{$_[0]->{val
}}; Mal
::List
->new([@arr[1..$#arr]]); }
133 sub slice
{ my @arr = @
{$_[0]->{val
}}; Mal
::List
->new([@arr[$_[1]..$_[2]]]); }
140 use parent
-norequire
, 'Mal::Sequence';
143 sub _list_Q
{ $_[0]->isa('Mal::List') }
150 use parent
-norequire
, 'Mal::Sequence';
153 sub _vector_Q
{ $_[0]->isa('Mal::Vector') }
159 package Mal
::HashMap
;
160 use overload
'%{}' => sub { no overloading
'%{}'; $_[0]->{val
} },
162 sub new
{ my $class = shift; bless {'meta'=>$nil, 'val'=>$_[0]}, $class }
163 sub meta
{ no overloading
'%{}'; $_[0]->{meta
} }
166 sub _hash_map
{ Mal
::HashMap
->new( { pairmap
{ $$a => $b } @_ } ) }
168 sub _hash_map_Q
{ $_[0]->isa('Mal::HashMap') }
174 package Mal
::Function
;
175 use overload
'&{}' => sub { my $f = shift; sub { $f->apply(\
@_) } },
179 my ($eval, $ast, $env, $params) = @_;
185 'ismacro'=>0}, $class
187 sub meta
{ $_[0]->{meta
} }
190 return Mal
::Env
->new($self->{env
}, $self->{params
}, $_[1]);
194 return &{ $self->{eval} }($self->{ast
}, gen_env
($self, $_[1]));
198 sub _sub_Q
{ $_[0]->isa('Mal::CoreFunction') || $_[0]->isa('Mal::FunctionRef') }
199 sub _function_Q
{ $_[0]->isa('Mal::Function') }
205 package Mal
::FunctionRef
;
206 use overload
'&{}' => sub { $_[0]->{code
} }, fallback
=> 1;
208 my ($class, $code) = @_;
210 'code'=>$code}, $class
212 sub meta
{ $_[0]->{meta
} }
218 package Mal
::CoreFunction
;
227 use overload
'${}' => sub { \
($_[0]->{val
}) }, fallback
=> 1;
228 sub new
{ my $class = shift; bless {'meta'=>$nil, 'val'=>$_[0]}, $class }
229 sub meta
{ $_[0]->{meta
} }
232 sub _atom_Q
{ $_[0]->isa('Mal::Atom') }