mirror of
https://github.com/kanaka/mal.git
synced 2024-11-14 00:09:01 +03:00
Perl: add step2_eval.
This commit is contained in:
parent
9af8aee63a
commit
a3b0621dbf
@ -30,7 +30,7 @@ Step Notes:
|
|||||||
- read_list
|
- read_list
|
||||||
- read_form until ')'
|
- read_form until ')'
|
||||||
- return array (boxed)
|
- return array (boxed)
|
||||||
- read_atom
|
- read_atom (not atom type)
|
||||||
- return scalar boxed type:
|
- return scalar boxed type:
|
||||||
- nil, true, false, symbol, integer, string
|
- nil, true, false, symbol, integer, string
|
||||||
- printer module:
|
- printer module:
|
||||||
@ -73,6 +73,7 @@ Step Notes:
|
|||||||
|
|
||||||
- step2_eval
|
- step2_eval
|
||||||
- types module:
|
- types module:
|
||||||
|
- symbol?, list? (if no simple idiomatic impl type check)
|
||||||
- first, rest, nth on list
|
- first, rest, nth on list
|
||||||
- eval_ast:
|
- eval_ast:
|
||||||
- if symbol, return value of looking up in env
|
- if symbol, return value of looking up in env
|
||||||
|
@ -26,6 +26,7 @@ sub _pr_str {
|
|||||||
return '{' . join(' ', @elems) . '}';
|
return '{' . join(' ', @elems) . '}';
|
||||||
}
|
}
|
||||||
when(/^String/) { return '"' . $$obj . '"'; }
|
when(/^String/) { return '"' . $$obj . '"'; }
|
||||||
|
when(/^CODE/) { return '<builtin_fn* ' . $obj . '>'; }
|
||||||
default { return $$obj; }
|
default { return $$obj; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ use Data::Dumper;
|
|||||||
sub tokenize {
|
sub tokenize {
|
||||||
my($str) = @_;
|
my($str) = @_;
|
||||||
my @tokens = $str =~ /[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/g;
|
my @tokens = $str =~ /[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/g;
|
||||||
return grep {not /^;|^$/} @tokens;
|
return grep {! /^;|^$/} @tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub read_atom {
|
sub read_atom {
|
||||||
|
80
perl/step2_eval.pl
Normal file
80
perl/step2_eval.pl
Normal 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";
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ our @EXPORT_OK = qw( $nil $true $false);
|
|||||||
|
|
||||||
{
|
{
|
||||||
package Nil;
|
package Nil;
|
||||||
#sub new { my $class = shift; bless {type=>'nil'} => $class }
|
|
||||||
sub new { my $class = shift; my $s = 'nil'; bless \$s => $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 }
|
sub new { my $class = shift; bless \$_[0] => $class }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
package Symbol;
|
package Symbol;
|
||||||
sub new { my $class = shift; bless \$_[0] => $class }
|
sub new { my $class = shift; bless \$_[0] => $class }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub _symbol_Q { ref $_[0] =~ /^Symbol/ }
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
package String;
|
package String;
|
||||||
sub new { my $class = shift; bless \$_[0] => $class }
|
sub new { my $class = shift; bless \$_[0] => $class }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
package List;
|
package List;
|
||||||
|
use Data::Dumper;
|
||||||
sub new { my $class = shift; bless $_[0], $class }
|
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;
|
package Vector;
|
||||||
sub new { my $class = shift; bless $_[0], $class }
|
sub new { my $class = shift; bless $_[0], $class }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
package HashMap;
|
package HashMap;
|
||||||
sub new { my $class = shift; bless $_[0], $class }
|
sub new { my $class = shift; bless $_[0], $class }
|
||||||
|
Loading…
Reference in New Issue
Block a user