aboutsummaryrefslogtreecommitdiff
path: root/perl
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-12-18 20:33:49 -0600
committerJoel Martin <github@martintribe.org>2015-01-09 16:16:50 -0600
commitb8ee29b22fbaa7a01f2754b4d6dd9af52e02017c (patch)
treef4d977ed220e9a3f665cfbf4f68770a81e4c2095 /perl
parentaaba249304b184e12e2445ab22d66df1f39a51a5 (diff)
downloadmal-b8ee29b22fbaa7a01f2754b4d6dd9af52e02017c.tar.gz
mal-b8ee29b22fbaa7a01f2754b4d6dd9af52e02017c.zip
All: add keywords.
Also, fix nth and count to match cloure.
Diffstat (limited to 'perl')
-rw-r--r--perl/core.pm25
-rw-r--r--perl/env.pm8
-rw-r--r--perl/printer.pm4
-rw-r--r--perl/reader.pm3
-rw-r--r--perl/readline.pm31
-rw-r--r--perl/step0.5_repl.pl33
-rw-r--r--perl/step1_read_print.pl5
-rw-r--r--perl/step2_eval.pl5
-rw-r--r--perl/step3_env.pl19
-rw-r--r--perl/step4_if_fn_do.pl15
-rw-r--r--perl/step5_tco.pl15
-rw-r--r--perl/step6_file.pl20
-rw-r--r--perl/step7_quote.pl20
-rw-r--r--perl/step8_macros.pl31
-rw-r--r--perl/step9_try.pl30
-rw-r--r--perl/stepA_interop.pl28
-rw-r--r--perl/types.pm12
17 files changed, 214 insertions, 90 deletions
diff --git a/perl/core.pm b/perl/core.pm
index eeee77e..7d70278 100644
--- a/perl/core.pm
+++ b/perl/core.pm
@@ -7,7 +7,8 @@ use Time::HiRes qw(time);
use readline;
use types qw(_sequential_Q _equal_Q _clone $nil $true $false
- _symbol_Q _nil_Q _true_Q _false_Q _list_Q _vector_Q
+ _nil_Q _true_Q _false_Q
+ _symbol _symbol_Q _keyword _keyword_Q _list_Q _vector_Q
_hash_map _hash_map_Q _assoc_BANG _dissoc_BANG _atom_Q);
use reader qw(read_str);
use printer qw(_pr_str);
@@ -101,12 +102,27 @@ sub concat {
List->new(\@new_arr);
}
-sub nth { my ($seq,$i) = @_; return scalar(@{$seq->{val}}) > $i ? $seq->nth($i) : $nil; }
+sub nth {
+ my ($seq,$i) = @_;
+ if (@{$seq->{val}} > $i) {
+ return scalar($seq->nth($i));
+ } else {
+ die "nth: index out of bounds";
+ }
+}
sub first { my ($seq) = @_; return scalar(@{$seq->{val}}) > 0 ? $seq->nth(0) : $nil; }
sub rest { return $_[0]->rest(); }
+sub count {
+ if (_nil_Q($_[0])) {
+ return Integer->new(0);
+ } else {
+ return Integer->new(scalar(@{$_[0]->{val}}))
+ }
+}
+
sub apply {
my @all_args = @{$_[0]->{val}};
my $f = $all_args[0];
@@ -167,7 +183,10 @@ our $core_ns = {
'nil?' => sub { _nil_Q($_[0]->nth(0)) ? $true : $false },
'true?' => sub { _true_Q($_[0]->nth(0)) ? $true : $false },
'false?' => sub { _false_Q($_[0]->nth(0)) ? $true : $false },
+ 'symbol' => sub { Symbol->new(${$_[0]->nth(0)}) },
'symbol?' => sub { _symbol_Q($_[0]->nth(0)) ? $true : $false },
+ 'keyword' => sub { _keyword(${$_[0]->nth(0)}) },
+ 'keyword?' => sub { _keyword_Q($_[0]->nth(0)) ? $true : $false },
'pr-str' => sub { pr_str($_[0]) },
'str' => sub { str($_[0]) },
@@ -206,7 +225,7 @@ our $core_ns = {
'cons' => sub { cons($_[0]->nth(0), $_[0]->nth(1)) },
'concat' => sub { concat(@{$_[0]->{val}}) },
'empty?' => sub { scalar(@{$_[0]->nth(0)->{val}}) == 0 ? $true : $false },
- 'count' => sub { Integer->new(scalar(@{$_[0]->nth(0)->{val}})) },
+ 'count' => sub { count($_[0]->nth(0)) },
'apply' => sub { apply($_[0]) },
'map' => sub { mal_map($_[0]->nth(0), $_[0]->nth(1)) },
'conj' => sub { die "not implemented\n"; },
diff --git a/perl/env.pm b/perl/env.pm
index 372eecd..8012565 100644
--- a/perl/env.pm
+++ b/perl/env.pm
@@ -28,20 +28,20 @@ use Exporter 'import';
}
sub find {
my ($self, $key) = @_;
- if (exists $self->{$key}) { return $self; }
+ if (exists $self->{$$key}) { return $self; }
elsif ($self->{__outer__}) { return $self->{__outer__}->find($key); }
else { return undef; }
}
sub set {
my ($self, $key, $value) = @_;
- $self->{$key} = $value;
+ $self->{$$key} = $value;
return $value
}
sub get {
my ($self, $key) = @_;
my $env = $self->find($key);
- die "'" . $key . "' not found\n" unless $env;
- return $env->{$key};
+ die "'" . $$key . "' not found\n" unless $env;
+ return $env->{$$key};
}
}
diff --git a/perl/printer.pm b/perl/printer.pm
index 9ce6707..7b00b1e 100644
--- a/perl/printer.pm
+++ b/perl/printer.pm
@@ -30,7 +30,9 @@ sub _pr_str {
return '{' . join(' ', @elems) . '}';
}
when(/^String/) {
- if ($_r) {
+ if ($$obj =~ /^\x{029e}/) {
+ return ':' . substr($$obj,1);
+ } elsif ($_r) {
my $str = $$obj;
$str =~ s/\\/\\\\/g;
$str =~ s/"/\\"/g;
diff --git a/perl/reader.pm b/perl/reader.pm
index cd4c565..501f992 100644
--- a/perl/reader.pm
+++ b/perl/reader.pm
@@ -6,7 +6,7 @@ no if $] >= 5.018, warnings => "experimental::smartmatch";
use Exporter 'import';
our @EXPORT_OK = qw( read_str );
-use types qw($nil $true $false _hash_map);
+use types qw($nil $true $false _keyword _hash_map);
use Data::Dumper;
@@ -37,6 +37,7 @@ sub read_atom {
$str =~ s/\\n/\n/g;
return String->new($str)
}
+ when(/^:/) { return _keyword(substr($token,1)) }
when(/^nil$/) { return $nil }
when(/^true$/) { return $true }
when(/^false$/) { return $false }
diff --git a/perl/readline.pm b/perl/readline.pm
index f0710b1..0629f39 100644
--- a/perl/readline.pm
+++ b/perl/readline.pm
@@ -1,12 +1,12 @@
# To get readline line editing functionality, please install
-# Term::ReadLine::Gnu (GPL) or Term::ReadLine::Perl (GPL, Artistic)
-# from CPAN.
+# Term::ReadKey and either Term::ReadLine::Gnu (GPL) or
+# Term::ReadLine::Perl (GPL, Artistic) from CPAN.
package readline;
use strict;
use warnings;
use Exporter 'import';
-our @EXPORT_OK = qw( mal_readline );
+our @EXPORT_OK = qw( mal_readline set_rl_mode );
use Term::ReadLine;
@@ -36,6 +36,13 @@ sub load_history {
close $fh;
}
+my $rl_mode = "terminal";
+
+sub set_rl_mode {
+ my($mode) = @_;
+ $rl_mode = $mode;
+}
+
sub mal_readline {
my($prompt) = @_;
my $line = undef;
@@ -44,11 +51,21 @@ sub mal_readline {
load_history();
}
- if (defined ($line = $_rl->readline($prompt))) {
- save_line($line);
- return $line;
+ if ($rl_mode eq "terminal") {
+ if (defined ($line = $_rl->readline($prompt))) {
+ save_line($line);
+ return $line;
+ } else {
+ return undef;
+ }
} else {
- return undef;
+ print "$prompt";
+ if (defined ($line = readline(*STDIN))) {
+ save_line($line);
+ return $line;
+ } else {
+ return undef;
+ }
}
}
1;
diff --git a/perl/step0.5_repl.pl b/perl/step0.5_repl.pl
new file mode 100644
index 0000000..d8a9d9f
--- /dev/null
+++ b/perl/step0.5_repl.pl
@@ -0,0 +1,33 @@
+use strict;
+use warnings FATAL => qw(all);
+use readline qw(readline);
+
+# read
+sub READ {
+ my $str = shift;
+ return $str;
+}
+
+# eval
+sub EVAL {
+ my($ast, $env) = @_;
+ return eval($ast);
+}
+
+# print
+sub PRINT {
+ my $exp = shift;
+ return $exp;
+}
+
+# repl
+sub REP {
+ my $str = shift;
+ return PRINT(EVAL(READ($str), {}));
+}
+
+while (1) {
+ my $line = readline("user> ");
+ if (! defined $line) { last; }
+ print(REP($line), "\n");
+}
diff --git a/perl/step1_read_print.pl b/perl/step1_read_print.pl
index 8288336..26c7bbf 100644
--- a/perl/step1_read_print.pl
+++ b/perl/step1_read_print.pl
@@ -3,7 +3,7 @@ use warnings FATAL => qw(all);
no if $] >= 5.018, warnings => "experimental::smartmatch";
use File::Basename;
use lib dirname (__FILE__);
-use readline qw(mal_readline);
+use readline qw(mal_readline set_rl_mode);
use feature qw(switch);
use reader;
@@ -33,6 +33,9 @@ sub REP {
return PRINT(EVAL(READ($str), {}));
}
+if (scalar(@ARGV) > 0 && $ARGV[0] eq "--raw") {
+ set_rl_mode("raw");
+}
while (1) {
my $line = mal_readline("user> ");
if (! defined $line) { last; }
diff --git a/perl/step2_eval.pl b/perl/step2_eval.pl
index c3759a5..858a385 100644
--- a/perl/step2_eval.pl
+++ b/perl/step2_eval.pl
@@ -3,7 +3,7 @@ use warnings FATAL => qw(all);
no if $] >= 5.018, warnings => "experimental::smartmatch";
use File::Basename;
use lib dirname (__FILE__);
-use readline qw(mal_readline);
+use readline qw(mal_readline set_rl_mode);
use feature qw(switch);
use Data::Dumper;
@@ -80,6 +80,9 @@ $repl_env->{'-'} = sub { Integer->new(${$_[0]->nth(0)} - ${$_[0]->nth(1)}) };
$repl_env->{'*'} = sub { Integer->new(${$_[0]->nth(0)} * ${$_[0]->nth(1)}) };
$repl_env->{'/'} = sub { Integer->new(${$_[0]->nth(0)} / ${$_[0]->nth(1)}) };
+if (scalar(@ARGV) > 0 && $ARGV[0] eq "--raw") {
+ set_rl_mode("raw");
+}
while (1) {
my $line = mal_readline("user> ");
if (! defined $line) { last; }
diff --git a/perl/step3_env.pl b/perl/step3_env.pl
index f63443d..1c34ab6 100644
--- a/perl/step3_env.pl
+++ b/perl/step3_env.pl
@@ -3,7 +3,7 @@ use warnings FATAL => qw(all);
no if $] >= 5.018, warnings => "experimental::smartmatch";
use File::Basename;
use lib dirname (__FILE__);
-use readline qw(mal_readline);
+use readline qw(mal_readline set_rl_mode);
use feature qw(switch);
use Data::Dumper;
@@ -23,7 +23,7 @@ sub eval_ast {
my($ast, $env) = @_;
given (ref $ast) {
when (/^Symbol/) {
- $env->get($$ast);
+ $env->get($ast);
}
when (/^List/) {
my @lst = map {EVAL($_, $env)} @{$ast->{val}};
@@ -58,12 +58,12 @@ sub EVAL {
given ($$a0) {
when (/^def!$/) {
my $res = EVAL($a2, $env);
- return $env->set($$a1, $res);
+ return $env->set($a1, $res);
}
when (/^let\*$/) {
my $let_env = Env->new($env);
for(my $i=0; $i < scalar(@{$a1->{val}}); $i+=2) {
- $let_env->set(${$a1->nth($i)}, EVAL($a1->nth($i+1), $let_env));
+ $let_env->set($a1->nth($i), EVAL($a1->nth($i+1), $let_env));
}
return EVAL($a2, $let_env);
}
@@ -88,11 +88,14 @@ sub REP {
return PRINT(EVAL(READ($str), $repl_env));
}
-$repl_env->set('+', sub { Integer->new(${$_[0]->nth(0)} + ${$_[0]->nth(1)}) } );
-$repl_env->set('-', sub { Integer->new(${$_[0]->nth(0)} - ${$_[0]->nth(1)}) } );
-$repl_env->set('*', sub { Integer->new(${$_[0]->nth(0)} * ${$_[0]->nth(1)}) } );
-$repl_env->set('/', sub { Integer->new(${$_[0]->nth(0)} / ${$_[0]->nth(1)}) } );
+$repl_env->set(Symbol->new('+'), sub { Integer->new(${$_[0]->nth(0)} + ${$_[0]->nth(1)}) } );
+$repl_env->set(Symbol->new('-'), sub { Integer->new(${$_[0]->nth(0)} - ${$_[0]->nth(1)}) } );
+$repl_env->set(Symbol->new('*'), sub { Integer->new(${$_[0]->nth(0)} * ${$_[0]->nth(1)}) } );
+$repl_env->set(Symbol->new('/'), sub { Integer->new(${$_[0]->nth(0)} / ${$_[0]->nth(1)}) } );
+if (scalar(@ARGV) > 0 && $ARGV[0] eq "--raw") {
+ set_rl_mode("raw");
+}
while (1) {
my $line = mal_readline("user> ");
if (! defined $line) { last; }
diff --git a/perl/step4_if_fn_do.pl b/perl/step4_if_fn_do.pl
index abf0c67..64ad314 100644
--- a/perl/step4_if_fn_do.pl
+++ b/perl/step4_if_fn_do.pl
@@ -3,7 +3,7 @@ use warnings FATAL => qw(all);
no if $] >= 5.018, warnings => "experimental::smartmatch";
use File::Basename;
use lib dirname (__FILE__);
-use readline qw(mal_readline);
+use readline qw(mal_readline set_rl_mode);
use feature qw(switch);
use Data::Dumper;
@@ -24,7 +24,7 @@ sub eval_ast {
my($ast, $env) = @_;
given (ref $ast) {
when (/^Symbol/) {
- $env->get($$ast);
+ $env->get($ast);
}
when (/^List/) {
my @lst = map {EVAL($_, $env)} @{$ast->{val}};
@@ -59,12 +59,12 @@ sub EVAL {
given ((ref $a0) =~ /^Symbol/ ? $$a0 : $a0) {
when (/^def!$/) {
my $res = EVAL($a2, $env);
- return $env->set($$a1, $res);
+ return $env->set($a1, $res);
}
when (/^let\*$/) {
my $let_env = Env->new($env);
for(my $i=0; $i < scalar(@{$a1->{val}}); $i+=2) {
- $let_env->set(${$a1->nth($i)}, EVAL($a1->nth($i+1), $let_env));
+ $let_env->set($a1->nth($i), EVAL($a1->nth($i+1), $let_env));
}
return EVAL($a2, $let_env);
}
@@ -109,11 +109,16 @@ sub REP {
}
# core.pl: defined using perl
-foreach my $n (%$core_ns) { $repl_env->set($n, $core_ns->{$n}); }
+foreach my $n (%$core_ns) {
+ $repl_env->set(Symbol->new($n), $core_ns->{$n});
+}
# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))");
+if (scalar(@ARGV) > 0 && $ARGV[0] eq "--raw") {
+ set_rl_mode("raw");
+}
while (1) {
my $line = mal_readline("user> ");
if (! defined $line) { last; }
diff --git a/perl/step5_tco.pl b/perl/step5_tco.pl
index 60dc13a..53255c2 100644
--- a/perl/step5_tco.pl
+++ b/perl/step5_tco.pl
@@ -3,7 +3,7 @@ use warnings FATAL => qw(all);
no if $] >= 5.018, warnings => "experimental::smartmatch";
use File::Basename;
use lib dirname (__FILE__);
-use readline qw(mal_readline);
+use readline qw(mal_readline set_rl_mode);
use feature qw(switch);
use Data::Dumper;
@@ -24,7 +24,7 @@ sub eval_ast {
my($ast, $env) = @_;
given (ref $ast) {
when (/^Symbol/) {
- $env->get($$ast);
+ $env->get($ast);
}
when (/^List/) {
my @lst = map {EVAL($_, $env)} @{$ast->{val}};
@@ -62,12 +62,12 @@ sub EVAL {
given ((ref $a0) =~ /^Symbol/ ? $$a0 : $a0) {
when (/^def!$/) {
my $res = EVAL($a2, $env);
- return $env->set($$a1, $res);
+ return $env->set($a1, $res);
}
when (/^let\*$/) {
my $let_env = Env->new($env);
for(my $i=0; $i < scalar(@{$a1->{val}}); $i+=2) {
- $let_env->set(${$a1->nth($i)}, EVAL($a1->nth($i+1), $let_env));
+ $let_env->set($a1->nth($i), EVAL($a1->nth($i+1), $let_env));
}
$ast = $a2;
$env = $let_env;
@@ -120,11 +120,16 @@ sub REP {
}
# core.pl: defined using perl
-foreach my $n (%$core_ns) { $repl_env->set($n, $core_ns->{$n}); }
+foreach my $n (%$core_ns) {
+ $repl_env->set(Symbol->new($n), $core_ns->{$n});
+}
# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))");
+if (scalar(@ARGV) > 0 && $ARGV[0] eq "--raw") {
+ set_rl_mode("raw");
+}
while (1) {
my $line = mal_readline("user> ");
if (! defined $line) { last; }
diff --git a/perl/step6_file.pl b/perl/step6_file.pl
index a95197a..48b835f 100644
--- a/perl/step6_file.pl
+++ b/perl/step6_file.pl
@@ -3,7 +3,7 @@ use warnings FATAL => qw(all);
no if $] >= 5.018, warnings => "experimental::smartmatch";
use File::Basename;
use lib dirname (__FILE__);
-use readline qw(mal_readline);
+use readline qw(mal_readline set_rl_mode);
use feature qw(switch);
use Data::Dumper;
@@ -24,7 +24,7 @@ sub eval_ast {
my($ast, $env) = @_;
given (ref $ast) {
when (/^Symbol/) {
- $env->get($$ast);
+ $env->get($ast);
}
when (/^List/) {
my @lst = map {EVAL($_, $env)} @{$ast->{val}};
@@ -62,12 +62,12 @@ sub EVAL {
given ((ref $a0) =~ /^Symbol/ ? $$a0 : $a0) {
when (/^def!$/) {
my $res = EVAL($a2, $env);
- return $env->set($$a1, $res);
+ return $env->set($a1, $res);
}
when (/^let\*$/) {
my $let_env = Env->new($env);
for(my $i=0; $i < scalar(@{$a1->{val}}); $i+=2) {
- $let_env->set(${$a1->nth($i)}, EVAL($a1->nth($i+1), $let_env));
+ $let_env->set($a1->nth($i), EVAL($a1->nth($i+1), $let_env));
}
$ast = $a2;
$env = $let_env;
@@ -120,15 +120,21 @@ sub REP {
}
# core.pl: defined using perl
-foreach my $n (%$core_ns) { $repl_env->set($n, $core_ns->{$n}); }
-$repl_env->set('eval', sub { EVAL($_[0]->nth(0), $repl_env); });
+foreach my $n (%$core_ns) {
+ $repl_env->set(Symbol->new($n), $core_ns->{$n});
+}
+$repl_env->set(Symbol->new('eval'), sub { EVAL($_[0]->nth(0), $repl_env); });
my @_argv = map {String->new($_)} @ARGV[1..$#ARGV];
-$repl_env->set('*ARGV*', List->new(\@_argv));
+$repl_env->set(Symbol->new('*ARGV*'), List->new(\@_argv));
# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))");
REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
+if (scalar(@ARGV) > 0 && $ARGV[0] eq "--raw") {
+ set_rl_mode("raw");
+ shift @ARGV;
+}
if (scalar(@ARGV) > 0) {
REP("(load-file \"" . $ARGV[0] . "\")");
exit 0;
diff --git a/perl/step7_quote.pl b/perl/step7_quote.pl
index 5ce9199..89133a2 100644
--- a/perl/step7_quote.pl
+++ b/perl/step7_quote.pl
@@ -3,7 +3,7 @@ use warnings FATAL => qw(all);
no if $] >= 5.018, warnings => "experimental::smartmatch";
use File::Basename;
use lib dirname (__FILE__);
-use readline qw(mal_readline);
+use readline qw(mal_readline set_rl_mode);
use feature qw(switch);
use Data::Dumper;
@@ -47,7 +47,7 @@ sub eval_ast {
my($ast, $env) = @_;
given (ref $ast) {
when (/^Symbol/) {
- $env->get($$ast);
+ $env->get($ast);
}
when (/^List/) {
my @lst = map {EVAL($_, $env)} @{$ast->{val}};
@@ -85,12 +85,12 @@ sub EVAL {
given ((ref $a0) =~ /^Symbol/ ? $$a0 : $a0) {
when (/^def!$/) {
my $res = EVAL($a2, $env);
- return $env->set($$a1, $res);
+ return $env->set($a1, $res);
}
when (/^let\*$/) {
my $let_env = Env->new($env);
for(my $i=0; $i < scalar(@{$a1->{val}}); $i+=2) {
- $let_env->set(${$a1->nth($i)}, EVAL($a1->nth($i+1), $let_env));
+ $let_env->set($a1->nth($i), EVAL($a1->nth($i+1), $let_env));
}
$ast = $a2;
$env = $let_env;
@@ -150,15 +150,21 @@ sub REP {
}
# core.pl: defined using perl
-foreach my $n (%$core_ns) { $repl_env->set($n, $core_ns->{$n}); }
-$repl_env->set('eval', sub { EVAL($_[0]->nth(0), $repl_env); });
+foreach my $n (%$core_ns) {
+ $repl_env->set(Symbol->new($n), $core_ns->{$n});
+}
+$repl_env->set(Symbol->new('eval'), sub { EVAL($_[0]->nth(0), $repl_env); });
my @_argv = map {String->new($_)} @ARGV[1..$#ARGV];
-$repl_env->set('*ARGV*', List->new(\@_argv));
+$repl_env->set(Symbol->new('*ARGV*'), List->new(\@_argv));
# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))");
REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
+if (scalar(@ARGV) > 0 && $ARGV[0] eq "--raw") {
+ set_rl_mode("raw");
+ shift @ARGV;
+}
if (scalar(@ARGV) > 0) {
REP("(load-file \"" . $ARGV[0] . "\")");
exit 0;
diff --git a/perl/step8_macros.pl b/perl/step8_macros.pl
index d95e032..4e4a48d 100644
--- a/perl/step8_macros.pl
+++ b/perl/step8_macros.pl
@@ -3,7 +3,7 @@ use warnings FATAL => qw(all);
no if $] >= 5.018, warnings => "experimental::smartmatch";
use File::Basename;
use lib dirname (__FILE__);
-use readline qw(mal_readline);
+use readline qw(mal_readline set_rl_mode);
use feature qw(switch);
use Data::Dumper;
@@ -47,8 +47,8 @@ sub is_macro_call {
my ($ast, $env) = @_;
if (_list_Q($ast) &&
_symbol_Q($ast->nth(0)) &&
- $env->find(${$ast->nth(0)})) {
- my ($f) = $env->get(${$ast->nth(0)});
+ $env->find($ast->nth(0))) {
+ my ($f) = $env->get($ast->nth(0));
if ((ref $f) =~ /^Function/) {
return $f->{ismacro};
}
@@ -59,7 +59,7 @@ sub is_macro_call {
sub macroexpand {
my ($ast, $env) = @_;
while (is_macro_call($ast, $env)) {
- my $mac = $env->get(${$ast->nth(0)});
+ my $mac = $env->get($ast->nth(0));
$ast = $mac->apply($ast->rest());
}
return $ast;
@@ -70,7 +70,7 @@ sub eval_ast {
my($ast, $env) = @_;
given (ref $ast) {
when (/^Symbol/) {
- $env->get($$ast);
+ $env->get($ast);
}
when (/^List/) {
my @lst = map {EVAL($_, $env)} @{$ast->{val}};
@@ -111,12 +111,12 @@ sub EVAL {
given ((ref $a0) =~ /^Symbol/ ? $$a0 : $a0) {
when (/^def!$/) {
my $res = EVAL($a2, $env);
- return $env->set($$a1, $res);
+ return $env->set($a1, $res);
}
when (/^let\*$/) {
my $let_env = Env->new($env);
for(my $i=0; $i < scalar(@{$a1->{val}}); $i+=2) {
- $let_env->set(${$a1->nth($i)}, EVAL($a1->nth($i+1), $let_env));
+ $let_env->set($a1->nth($i), EVAL($a1->nth($i+1), $let_env));
}
$ast = $a2;
$env = $let_env;
@@ -132,7 +132,7 @@ sub EVAL {
when (/^defmacro!$/) {
my $func = EVAL($a2, $env);
$func->{ismacro} = 1;
- return $env->set($$a1, $func);
+ return $env->set($a1, $func);
}
when (/^macroexpand$/) {
return macroexpand($a1, $env);
@@ -184,15 +184,24 @@ sub REP {
}
# core.pl: defined using perl
-foreach my $n (%$core_ns) { $repl_env->set($n, $core_ns->{$n}); }
-$repl_env->set('eval', sub { EVAL($_[0]->nth(0), $repl_env); });
+foreach my $n (%$core_ns) {
+ $repl_env->set(Symbol->new($n), $core_ns->{$n});
+}
+$repl_env->set(Symbol->new('eval'), sub { EVAL($_[0]->nth(0), $repl_env); });
my @_argv = map {String->new($_)} @ARGV[1..$#ARGV];
-$repl_env->set('*ARGV*', List->new(\@_argv));
+$repl_env->set(Symbol->new('*ARGV*'), List->new(\@_argv));
# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))");
REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
+REP("(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)))))))");
+REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))");
+
+if (scalar(@ARGV) > 0 && $ARGV[0] eq "--raw") {
+ set_rl_mode("raw");
+ shift @ARGV;
+}
if (scalar(@ARGV) > 0) {
REP("(load-file \"" . $ARGV[0] . "\")");
exit 0;
diff --git a/perl/step9_try.pl b/perl/step9_try.pl
index 5862ef1..ec823bc 100644
--- a/perl/step9_try.pl
+++ b/perl/step9_try.pl
@@ -3,7 +3,7 @@ use warnings FATAL => qw(all);
no if $] >= 5.018, warnings => "experimental::smartmatch";
use File::Basename;
use lib dirname (__FILE__);
-use readline qw(mal_readline);
+use readline qw(mal_readline set_rl_mode);
use feature qw(switch);
use Data::Dumper;
@@ -48,8 +48,8 @@ sub is_macro_call {
my ($ast, $env) = @_;
if (_list_Q($ast) &&
_symbol_Q($ast->nth(0)) &&
- $env->find(${$ast->nth(0)})) {
- my ($f) = $env->get(${$ast->nth(0)});
+ $env->find($ast->nth(0))) {
+ my ($f) = $env->get($ast->nth(0));
if ((ref $f) =~ /^Function/) {
return $f->{ismacro};
}
@@ -60,7 +60,7 @@ sub is_macro_call {
sub macroexpand {
my ($ast, $env) = @_;
while (is_macro_call($ast, $env)) {
- my $mac = $env->get(${$ast->nth(0)});
+ my $mac = $env->get($ast->nth(0));
$ast = $mac->apply($ast->rest());
}
return $ast;
@@ -71,7 +71,7 @@ sub eval_ast {
my($ast, $env) = @_;
given (ref $ast) {
when (/^Symbol/) {
- $env->get($$ast);
+ $env->get($ast);
}
when (/^List/) {
my @lst = map {EVAL($_, $env)} @{$ast->{val}};
@@ -112,12 +112,12 @@ sub EVAL {
given ((ref $a0) =~ /^Symbol/ ? $$a0 : $a0) {
when (/^def!$/) {
my $res = EVAL($a2, $env);
- return $env->set($$a1, $res);
+ return $env->set($a1, $res);
}
when (/^let\*$/) {
my $let_env = Env->new($env);
for(my $i=0; $i < scalar(@{$a1->{val}}); $i+=2) {
- $let_env->set(${$a1->nth($i)}, EVAL($a1->nth($i+1), $let_env));
+ $let_env->set($a1->nth($i), EVAL($a1->nth($i+1), $let_env));
}
$ast = $a2;
$env = $let_env;
@@ -133,7 +133,7 @@ sub EVAL {
when (/^defmacro!$/) {
my $func = EVAL($a2, $env);
$func->{ismacro} = 1;
- return $env->set($$a1, $func);
+ return $env->set($a1, $func);
}
when (/^macroexpand$/) {
return macroexpand($a1, $env);
@@ -212,24 +212,28 @@ sub REP {
}
# core.pl: defined using perl
-foreach my $n (%$core_ns) { $repl_env->set($n, $core_ns->{$n}); }
-$repl_env->set('eval', sub { EVAL($_[0]->nth(0), $repl_env); });
+foreach my $n (%$core_ns) {
+ $repl_env->set(Symbol->new($n), $core_ns->{$n});
+}
+$repl_env->set(Symbol->new('eval'), sub { EVAL($_[0]->nth(0), $repl_env); });
my @_argv = map {String->new($_)} @ARGV[1..$#ARGV];
-$repl_env->set('*ARGV*', List->new(\@_argv));
+$repl_env->set(Symbol->new('*ARGV*'), List->new(\@_argv));
# core.mal: defined using the language itself
-REP("(def! *host-language* \"javascript\")");
REP("(def! not (fn* (a) (if a false true)))");
REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
REP("(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)))))))");
REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))");
+if (scalar(@ARGV) > 0 && $ARGV[0] eq "--raw") {
+ set_rl_mode("raw");
+ shift @ARGV;
+}
if (scalar(@ARGV) > 0) {
REP("(load-file \"" . $ARGV[0] . "\")");
exit 0;
}
-REP("(println (str \"Mal [\" *host-language* \"]\"))");
while (1) {
my $line = mal_readline("user> ");
if (! defined $line) { last; }
diff --git a/perl/stepA_interop.pl b/perl/stepA_interop.pl
index 0605d57..7993635 100644
--- a/perl/stepA_interop.pl
+++ b/perl/stepA_interop.pl
@@ -3,7 +3,7 @@ use warnings FATAL => qw(all);
no if $] >= 5.018, warnings => "experimental::smartmatch";
use File::Basename;
use lib dirname (__FILE__);
-use readline qw(mal_readline);
+use readline qw(mal_readline set_rl_mode);
use feature qw(switch);
use Data::Dumper;
@@ -48,8 +48,8 @@ sub is_macro_call {
my ($ast, $env) = @_;
if (_list_Q($ast) &&
_symbol_Q($ast->nth(0)) &&
- $env->find(${$ast->nth(0)})) {
- my ($f) = $env->get(${$ast->nth(0)});
+ $env->find($ast->nth(0))) {
+ my ($f) = $env->get($ast->nth(0));
if ((ref $f) =~ /^Function/) {
return $f->{ismacro};
}
@@ -60,7 +60,7 @@ sub is_macro_call {
sub macroexpand {
my ($ast, $env) = @_;
while (is_macro_call($ast, $env)) {
- my $mac = $env->get(${$ast->nth(0)});
+ my $mac = $env->get($ast->nth(0));
$ast = $mac->apply($ast->rest());
}
return $ast;
@@ -71,7 +71,7 @@ sub eval_ast {
my($ast, $env) = @_;
given (ref $ast) {
when (/^Symbol/) {
- $env->get($$ast);
+ $env->get($ast);
}
when (/^List/) {
my @lst = map {EVAL($_, $env)} @{$ast->{val}};
@@ -112,12 +112,12 @@ sub EVAL {
given ((ref $a0) =~ /^Symbol/ ? $$a0 : $a0) {
when (/^def!$/) {
my $res = EVAL($a2, $env);
- return $env->set($$a1, $res);
+ return $env->set($a1, $res);
}
when (/^let\*$/) {
my $let_env = Env->new($env);
for(my $i=0; $i < scalar(@{$a1->{val}}); $i+=2) {
- $let_env->set(${$a1->nth($i)}, EVAL($a1->nth($i+1), $let_env));
+ $let_env->set($a1->nth($i), EVAL($a1->nth($i+1), $let_env));
}
$ast = $a2;
$env = $let_env;
@@ -133,7 +133,7 @@ sub EVAL {
when (/^defmacro!$/) {
my $func = EVAL($a2, $env);
$func->{ismacro} = 1;
- return $env->set($$a1, $func);
+ return $env->set($a1, $func);
}
when (/^macroexpand$/) {
return macroexpand($a1, $env);
@@ -215,10 +215,12 @@ sub REP {
}
# core.pl: defined using perl
-foreach my $n (%$core_ns) { $repl_env->set($n, $core_ns->{$n}); }
-$repl_env->set('eval', sub { EVAL($_[0]->nth(0), $repl_env); });
+foreach my $n (%$core_ns) {
+ $repl_env->set(Symbol->new($n), $core_ns->{$n});
+}
+$repl_env->set(Symbol->new('eval'), sub { EVAL($_[0]->nth(0), $repl_env); });
my @_argv = map {String->new($_)} @ARGV[1..$#ARGV];
-$repl_env->set('*ARGV*', List->new(\@_argv));
+$repl_env->set(Symbol->new('*ARGV*'), List->new(\@_argv));
# core.mal: defined using the language itself
REP("(def! *host-language* \"javascript\")");
@@ -228,6 +230,10 @@ REP("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (
REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))");
+if (scalar(@ARGV) > 0 && $ARGV[0] eq "--raw") {
+ set_rl_mode("raw");
+ shift @ARGV;
+}
if (scalar(@ARGV) > 0) {
REP("(load-file \"" . $ARGV[0] . "\")");
exit 0;
diff --git a/perl/types.pm b/perl/types.pm
index 356f8c6..e2d919c 100644
--- a/perl/types.pm
+++ b/perl/types.pm
@@ -5,10 +5,9 @@ no if $] >= 5.018, warnings => "experimental::smartmatch";
use feature qw(switch);
use Exporter 'import';
our @EXPORT_OK = qw(_sequential_Q _equal_Q _clone
- $nil $true $false
- _symbol_Q _nil_Q _true_Q _false_Q _list_Q _vector_Q
- _hash_map _hash_map_Q _assoc_BANG _dissoc_BANG
- _atom_Q);
+ $nil $true $false _nil_Q _true_Q _false_Q
+ _symbol _symbol_Q _keyword _keyword_Q _list_Q _vector_Q
+ _hash_map _hash_map_Q _assoc_BANG _dissoc_BANG _atom_Q);
use Data::Dumper;
@@ -111,10 +110,13 @@ sub _false_Q { return $_[0] eq $false }
package Symbol;
sub new { my $class = shift; bless \$_[0] => $class }
}
-
sub _symbol_Q { (ref $_[0]) =~ /^Symbol/ }
+sub _keyword { return String->new(("\x{029e}".$_[0])); }
+sub _keyword_Q { ((ref $_[0]) =~ /^String/) && ${$_[0]} =~ /^\x{029e}/; }
+
+
{
package String;
sub new { my $class = shift; bless \$_[0] => $class }