2 use feature
qw(switch);
6 our @EXPORT_OK = qw( read_str );
8 use types
qw($nil $true $false);
16 bless { position => 0, tokens => shift } => $class
18 sub next { my $self = shift; return $self->{tokens}[$self->{position}++] }
19 sub peek { my $self = shift; return $self->{tokens}[$self->{position}] }
24 my @tokens = $str =~ /[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/g;
25 return grep {not /^;|^$/} @tokens;
30 my $token = $rdr->next();
32 when(/^-?[0-9]+$/) { return Integer->new($token) }
33 when(/^"/) { return String->new(substr $token, 1, -1) }
34 when(/^nil$/) { return $nil }
35 when(/^true$/) { return $true }
36 when(/^false$/) { return $false }
37 default { return Symbol->new($token) }
42 my($rdr,$class,$start,$end) = @_;
43 $start = $start || '(';
46 my $token = $rdr->next();
48 if ($token ne $start) {
49 die "expected '$start'";
51 while (($token = $rdr->peek()) ne $end) {
52 if (! defined $token) {
53 die "expected '$end', got EOF";
55 push(@lst, read_form($rdr));
58 if ($class eq 'List') {
59 return List->new(\@lst);
60 } elsif ($class eq 'Vector') {
61 return Vector->new(\@lst);
64 for(my $i=0; $i<$#lst; $i+=2) {
66 $hsh->{$$str} = $lst[$i+1];
68 return HashMap->new($hsh);
74 my $token = $rdr->peek();
76 when(')') { die "unexpected ')'"; }
77 when('(') { return read_list($rdr, 'List'); }
78 when(']') { die "unexpected ']'"; }
79 when('[') { return read_list($rdr, 'Vector', '[', ']'); }
80 when('}') { die "unexpected '}'"; }
81 when('{') { return read_list($rdr, 'HashMap', '{', '}'); }
82 default { return read_atom($rdr); }
88 my @tokens = tokenize($str);
89 #print join(" / ", @tokens) . "\n";
90 return read_form(Reader->new(\@tokens));
93 #print Dumper(read_str("123"));
94 #print Dumper(read_str("+"));
95 #print Dumper(read_str("\"abc\""));
96 #print Dumper(read_str("nil"));
97 #print Dumper(read_str("true"));
98 #print Dumper(read_str("false"));
99 #print Dumper(read_str("(+ 2 3)"));
100 #print Dumper(read_str("(foo 2 (3 4))"));