perl: Replace _clone() with a ->clone method.
[jackhill/mal.git] / perl / step9_try.pl
index 745e44f..2f1a175 100644 (file)
@@ -1,14 +1,16 @@
 use strict;
-use warnings FATAL => qw(all);
+use warnings FATAL => "recursion";
 no if $] >= 5.018, warnings => "experimental::smartmatch";
+use feature qw(switch);
 use File::Basename;
 use lib dirname (__FILE__);
-use List::Util qw(pairs pairmap);
-use readline qw(mal_readline set_rl_mode);
-use feature qw(switch);
+
 use Data::Dumper;
+use List::Util qw(pairs pairmap);
+use Scalar::Util qw(blessed);
 
-use types qw($nil $true $false _sequential_Q _symbol_Q _list_Q _clone);
+use readline qw(mal_readline set_rl_mode);
+use types qw($nil $true $false _symbol_Q _list_Q);
 use reader;
 use printer;
 use env;
@@ -24,7 +26,7 @@ sub READ {
 # eval
 sub is_pair {
     my ($x) = @_;
-    return _sequential_Q($x) && @$x;
+    return $x->isa('Mal::Sequence') && @$x;
 }
 
 sub quasiquote {
@@ -124,7 +126,7 @@ sub EVAL {
             # Continue loop (TCO)
         }
         when ('defmacro!') {
-            my $func = _clone(EVAL($a2, $env));
+            my $func = EVAL($a2, $env)->clone;
             $func->{ismacro} = 1;
             return $env->set($a1, $func);
         }
@@ -132,32 +134,22 @@ sub EVAL {
             return macroexpand($a1, $env);
         }
         when ('try*') {
-            do {
-                local $@;
-                my $ret;
-                eval {
-                    use autodie; # always "throw" errors
-                    $ret = EVAL($a1, $env);
-                     1;
-                } or do {
-                    my $err = $@;
-                    if ($a2 && ${$a2->[0]} eq 'catch*') {
-                        my $exc;
-                        if (ref $err) {
-                            $exc = $err;
-                        } else {
-                            $exc = Mal::String->new(substr $err, 0, -1);
-                        }
-                       my $catch_env =
-                           Mal::Env->new($env, Mal::List->new([$a2->[1]]),
-                                               Mal::List->new([$exc]));
-                        return EVAL($a2->[2], $catch_env)
-                    } else {
-                        die $err;
-                    }
-                };
-                return $ret;
-            };
+           local $@;
+           my $ret = eval { EVAL($a1, $env) };
+           return $ret unless $@;
+           if ($a2 && ${$a2->[0]} eq 'catch*') {
+               my $exc;
+               if (defined(blessed $@) && $@->isa('Mal::Type')) {
+                   $exc = $@;
+               } else {
+                   chomp(my $msg = $@);
+                   $exc = Mal::String->new($msg);
+               }
+               my $catch_env = Mal::Env->new($env, [$a2->[1]], [$exc]);
+               return EVAL($a2->[2], $catch_env)
+           } else {
+               die $@;
+           }
         }
         when ('do') {
             eval_ast($ast->slice(1, $#$ast-1), $env);
@@ -216,10 +208,9 @@ $repl_env->set(Mal::Symbol->new('*ARGV*'), Mal::List->new(\@_argv));
 
 # core.mal: defined using the language itself
 REP(q[(def! not (fn* (a) (if a false true)))]);
-REP(q[(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")")))))]);
+REP(q[(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) "\nnil)")))))]);
 REP(q[(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw "odd number of forms to cond")) (cons 'cond (rest (rest xs)))))))]);
 
-
 if (@ARGV && $ARGV[0] eq "--raw") {
     set_rl_mode("raw");
     shift @ARGV;
@@ -235,20 +226,17 @@ while (1) {
         local $@;
         my $ret;
         eval {
-            use autodie; # always "throw" errors
             print(REP($line), "\n");
             1;
         } or do {
             my $err = $@;
-           if ($err->isa('Mal::BlankException')) {
+           if (defined(blessed $err) && $err->isa('Mal::BlankException')) {
                # ignore and continue
+           } elsif (defined(blessed $err) && $err->isa('Mal::Type')) {
+               print "Error: ".printer::_pr_str($err)."\n";
            } else {
-               if (ref $err) {
-                   print "Error: ".printer::_pr_str($err)."\n";
-               } else {
-                   chomp $err;
-                   print "Error: $err\n";
-               }
+               chomp $err;
+               print "Error: $err\n";
            }
         };
     };