2 use feature
qw(switch);
4 use warnings FATAL
=> qw(all);
6 our @EXPORT_OK = qw( read_str );
8 use types
qw($nil $true $false _hash_map);
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 {! /^;|^$/} @tokens;
30 my $token = $rdr->next();
32 when(/^-?[0-9]+$/) { return Integer->new($token) }
34 my $str = substr $token, 1, -1;
37 return String->new($str)
39 when(/^nil$/) { return $nil }
40 when(/^true$/) { return $true }
41 when(/^false$/) { return $false }
42 default { return Symbol->new($token) }
47 my($rdr,$class,$start,$end) = @_;
48 $start = $start || '(';
51 my $token = $rdr->next();
53 if ($token ne $start) {
54 die "expected '$start'";
56 while (($token = $rdr->peek()) ne $end) {
57 if (! defined $token) {
58 die "expected '$end', got EOF";
60 push(@lst, read_form($rdr));
63 if ($class eq 'List') {
64 return List->new(\@lst);
65 } elsif ($class eq 'Vector') {
66 return Vector->new(\@lst);
68 return _hash_map(@lst);
74 my $token = $rdr->peek();
76 when("'") { $rdr->next(); List->new([Symbol->new('quote'),
78 when('`') { $rdr->next(); List->new([Symbol->new('quasiquote'),
80 when('~') { $rdr->next(); List->new([Symbol->new('unquote'),
82 when('~@') { $rdr->next(); List->new([Symbol->new('splice-unquote'),
84 when(')') { die "unexpected ')'" }
85 when('(') { return read_list($rdr, 'List') }
86 when(']') { die "unexpected ']'" }
87 when('[') { return read_list($rdr, 'Vector', '[', ']') }
88 when('}') { die "unexpected '}'" }
89 when('{') { return read_list($rdr, 'HashMap', '{', '}') }
90 default { return read_atom($rdr) }
96 my @tokens = tokenize($str);
97 #print join(" / ", @tokens) . "\n";
98 return read_form(Reader->new(\@tokens));
101 #print Dumper(read_str("123"));
102 #print Dumper(read_str("+"));
103 #print Dumper(read_str("\"abc\""));
104 #print Dumper(read_str("nil"));
105 #print Dumper(read_str("true"));
106 #print Dumper(read_str("false"));
107 #print Dumper(read_str("(+ 2 3)"));
108 #print Dumper(read_str("(foo 2 (3 4))"));