1
1
mirror of https://github.com/kanaka/mal.git synced 2024-11-13 01:43:50 +03:00

Perl: add step2_eval.

This commit is contained in:
Joel Martin 2014-04-20 21:50:52 -05:00
parent 9af8aee63a
commit a3b0621dbf
5 changed files with 95 additions and 3 deletions

View File

@ -30,7 +30,7 @@ Step Notes:
- read_list
- read_form until ')'
- return array (boxed)
- read_atom
- read_atom (not atom type)
- return scalar boxed type:
- nil, true, false, symbol, integer, string
- printer module:
@ -73,6 +73,7 @@ Step Notes:
- step2_eval
- types module:
- symbol?, list? (if no simple idiomatic impl type check)
- first, rest, nth on list
- eval_ast:
- if symbol, return value of looking up in env

View File

@ -26,6 +26,7 @@ sub _pr_str {
return '{' . join(' ', @elems) . '}';
}
when(/^String/) { return '"' . $$obj . '"'; }
when(/^CODE/) { return '<builtin_fn* ' . $obj . '>'; }
default { return $$obj; }
}
}

View File

@ -22,7 +22,7 @@ use Data::Dumper;
sub tokenize {
my($str) = @_;
my @tokens = $str =~ /[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/g;
return grep {not /^;|^$/} @tokens;
return grep {! /^;|^$/} @tokens;
}
sub read_atom {

80
perl/step2_eval.pl Normal file
View File

@ -0,0 +1,80 @@
use strict;
use warnings;
use readline qw(readline);
use feature qw(switch);
use Data::Dumper;
use reader;
use printer;
# read
sub READ {
my $str = shift;
return reader::read_str($str);
}
# eval
sub eval_ast {
my($ast, $env) = @_;
given (ref $ast) {
when (/^Symbol/) {
if (exists $env->{$$ast}) {
return $env->{$$ast};
} else {
die "'" . $$ast . "' not found";
}
}
when (/^List/) {
my @lst = map {EVAL($_, $env)} @$ast;
return List->new(\@lst);
}
default {
return $ast;
}
}
}
sub EVAL {
my($ast, $env) = @_;
#print "EVAL: " . printer::_pr_str($ast) . "\n";
if (! ((ref $ast) =~ /^List/)) {
return eval_ast($ast, $env);
}
# apply list
my $el = eval_ast($ast, $env);
my $f = $el->[0];
return &{ $f }($el->rest());
}
# print
sub PRINT {
my $exp = shift;
return printer::_pr_str($exp);
}
# repl
my $repl_env = {};
sub REP {
my $str = shift;
return PRINT(EVAL(READ($str), $repl_env));
}
$repl_env->{'+'} = sub { Integer->new(${$_[0][0]} + ${$_[0][1]}) };
$repl_env->{'-'} = sub { Integer->new(${$_[0][0]} - ${$_[0][1]}) };
$repl_env->{'*'} = sub { Integer->new(${$_[0][0]} * ${$_[0][1]}) };
$repl_env->{'/'} = sub { Integer->new(${$_[0][0]} / ${$_[0][1]}) };
while (1) {
my $line = readline("user> ");
if (! defined $line) { last; }
eval {
use autodie; # always "throw" errors
print(REP($line), "\n");
1;
};
if (my $err = $@) {
chomp $err;
print "Error: $err\n";
}
}

View File

@ -6,7 +6,6 @@ our @EXPORT_OK = qw( $nil $true $false);
{
package Nil;
#sub new { my $class = shift; bless {type=>'nil'} => $class }
sub new { my $class = shift; my $s = 'nil'; bless \$s => $class }
}
{
@ -27,26 +26,37 @@ our $false = False->new();
sub new { my $class = shift; bless \$_[0] => $class }
}
{
package Symbol;
sub new { my $class = shift; bless \$_[0] => $class }
}
sub _symbol_Q { ref $_[0] =~ /^Symbol/ }
{
package String;
sub new { my $class = shift; bless \$_[0] => $class }
}
{
package List;
use Data::Dumper;
sub new { my $class = shift; bless $_[0], $class }
sub rest { my @arr = @{$_[0]}; List->new([@arr[1..$#arr]]); }
}
sub _list_Q { ref $_[0] =~ /^Symbol/ }
{
package Vector;
sub new { my $class = shift; bless $_[0], $class }
}
{
package HashMap;
sub new { my $class = shift; bless $_[0], $class }