diff options
| author | Joel Martin <github@martintribe.org> | 2014-12-18 20:33:49 -0600 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-01-09 16:16:50 -0600 |
| commit | b8ee29b22fbaa7a01f2754b4d6dd9af52e02017c (patch) | |
| tree | f4d977ed220e9a3f665cfbf4f68770a81e4c2095 /perl | |
| parent | aaba249304b184e12e2445ab22d66df1f39a51a5 (diff) | |
| download | mal-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.pm | 25 | ||||
| -rw-r--r-- | perl/env.pm | 8 | ||||
| -rw-r--r-- | perl/printer.pm | 4 | ||||
| -rw-r--r-- | perl/reader.pm | 3 | ||||
| -rw-r--r-- | perl/readline.pm | 31 | ||||
| -rw-r--r-- | perl/step0.5_repl.pl | 33 | ||||
| -rw-r--r-- | perl/step1_read_print.pl | 5 | ||||
| -rw-r--r-- | perl/step2_eval.pl | 5 | ||||
| -rw-r--r-- | perl/step3_env.pl | 19 | ||||
| -rw-r--r-- | perl/step4_if_fn_do.pl | 15 | ||||
| -rw-r--r-- | perl/step5_tco.pl | 15 | ||||
| -rw-r--r-- | perl/step6_file.pl | 20 | ||||
| -rw-r--r-- | perl/step7_quote.pl | 20 | ||||
| -rw-r--r-- | perl/step8_macros.pl | 31 | ||||
| -rw-r--r-- | perl/step9_try.pl | 30 | ||||
| -rw-r--r-- | perl/stepA_interop.pl | 28 | ||||
| -rw-r--r-- | perl/types.pm | 12 |
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 } |
