| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Language::LispPerl::Reader; | 
| 2 |  |  |  |  |  |  | $Language::LispPerl::Reader::VERSION = '0.006'; | 
| 3 | 6 |  |  | 6 |  | 20 | use strict; | 
|  | 6 |  |  |  |  | 10 |  | 
|  | 6 |  |  |  |  | 139 |  | 
| 4 | 6 |  |  | 6 |  | 23 | use warnings; | 
|  | 6 |  |  |  |  | 44 |  | 
|  | 6 |  |  |  |  | 156 |  | 
| 5 | 6 |  |  | 6 |  | 1854 | use Language::LispPerl::Seq; | 
|  | 6 |  |  |  |  | 14 |  | 
|  | 6 |  |  |  |  | 290 |  | 
| 6 | 6 |  |  | 6 |  | 3246 | use Language::LispPerl::Atom; | 
|  | 6 |  |  |  |  | 15 |  | 
|  | 6 |  |  |  |  | 198 |  | 
| 7 | 6 |  |  | 6 |  | 35 | use Language::LispPerl::Logger; | 
|  | 6 |  |  |  |  | 7 |  | 
|  | 6 |  |  |  |  | 96 |  | 
| 8 |  |  |  |  |  |  |  | 
| 9 | 6 |  |  | 6 |  | 21 | use Carp; | 
|  | 6 |  |  |  |  | 8 |  | 
|  | 6 |  |  |  |  | 371 |  | 
| 10 | 6 |  |  | 6 |  | 21 | use Class::Load; | 
|  | 6 |  |  |  |  | 6 |  | 
|  | 6 |  |  |  |  | 11764 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | sub from_perl{ | 
| 13 | 680 |  |  | 680 | 0 | 480 | my ($thing) = @_; | 
| 14 | 680 |  |  |  |  | 459 | my $refthing = ref($thing); | 
| 15 | 680 | 100 |  |  |  | 750 | unless( $refthing ){ | 
| 16 | 525 |  |  |  |  | 2546 | return $thing; | 
| 17 |  |  |  |  |  |  | } | 
| 18 | 155 | 100 |  |  |  | 198 | if( $refthing eq 'HASH' ){ | 
| 19 | 128 | 100 |  |  |  | 183 | if( my $class = $thing->{__class} ){ | 
| 20 | 65 |  |  |  |  | 103 | Class::Load::load_class( $class ); | 
| 21 | 65 |  |  |  |  | 1045 | return $class->from_hash( $thing ); | 
| 22 |  |  |  |  |  |  | } | 
| 23 |  |  |  |  |  |  | return { | 
| 24 | 63 |  |  |  |  | 142 | map{ $_ => from_perl( $thing->{$_} ) } keys %$thing | 
|  | 185 |  |  |  |  | 202 |  | 
| 25 |  |  |  |  |  |  | }; | 
| 26 |  |  |  |  |  |  | } | 
| 27 | 27 | 50 |  |  |  | 43 | if( $refthing eq 'ARRAY' ){ | 
| 28 | 27 |  |  |  |  | 45 | return [ map{ from_perl( $_ ) } @$thing ]; | 
|  | 48 |  |  |  |  | 60 |  | 
| 29 |  |  |  |  |  |  | } | 
| 30 | 0 |  |  |  |  | 0 | confess("No idea how to turn $thing into objects"); | 
| 31 |  |  |  |  |  |  | } | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | sub new { | 
| 34 | 108 |  |  | 108 | 0 | 144 | my $class = shift; | 
| 35 | 108 |  |  |  |  | 678 | my $self  = { | 
| 36 |  |  |  |  |  |  | class       => $class, | 
| 37 |  |  |  |  |  |  | ast         => {}, | 
| 38 |  |  |  |  |  |  | nest        => 0, | 
| 39 |  |  |  |  |  |  | filehandler => undef, | 
| 40 |  |  |  |  |  |  | filename    => "unknown", | 
| 41 |  |  |  |  |  |  | line        => 1, | 
| 42 |  |  |  |  |  |  | col         => 1 | 
| 43 |  |  |  |  |  |  | }; | 
| 44 | 108 |  |  |  |  | 173 | bless $self; | 
| 45 | 108 |  |  |  |  | 207 | return $self; | 
| 46 |  |  |  |  |  |  | } | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | sub class { | 
| 49 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 50 | 0 |  |  |  |  | 0 | return $self->{class}; | 
| 51 |  |  |  |  |  |  | } | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | sub filehandler { | 
| 54 | 34404 |  |  | 34404 | 0 | 21095 | my $self = shift; | 
| 55 | 34404 |  |  |  |  | 19840 | my $fh   = shift; | 
| 56 | 34404 | 100 |  |  |  | 31665 | if ( defined $fh ) { | 
| 57 | 108 |  |  |  |  | 177 | $self->{filehandler} = $fh; | 
| 58 |  |  |  |  |  |  | } | 
| 59 |  |  |  |  |  |  | else { | 
| 60 | 34296 |  |  |  |  | 31441 | return $self->{filehandler}; | 
| 61 |  |  |  |  |  |  | } | 
| 62 |  |  |  |  |  |  | } | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | sub filename { | 
| 65 | 2286 |  |  | 2286 | 0 | 1829 | my $self = shift; | 
| 66 | 2286 |  |  |  |  | 1775 | my $fn   = shift; | 
| 67 | 2286 | 100 |  |  |  | 2725 | if ( defined $fn ) { | 
| 68 | 108 |  |  |  |  | 145 | $self->{filename} = $fn; | 
| 69 |  |  |  |  |  |  | } | 
| 70 |  |  |  |  |  |  | else { | 
| 71 | 2178 |  |  |  |  | 4035 | return $self->{filename}; | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  | } | 
| 74 |  |  |  |  |  |  |  | 
| 75 |  |  |  |  |  |  | sub line { | 
| 76 | 2872 |  |  | 2872 | 0 | 2189 | my $self = shift; | 
| 77 | 2872 |  |  |  |  | 1972 | my $line = shift; | 
| 78 | 2872 | 100 |  |  |  | 2891 | if ( defined $line ) { | 
| 79 | 401 |  |  |  |  | 367 | $self->{line} = $line; | 
| 80 |  |  |  |  |  |  | } | 
| 81 |  |  |  |  |  |  | else { | 
| 82 | 2471 |  |  |  |  | 3406 | return $self->{line}; | 
| 83 |  |  |  |  |  |  | } | 
| 84 |  |  |  |  |  |  | } | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | sub col { | 
| 87 | 18425 |  |  | 18425 | 0 | 12180 | my $self = shift; | 
| 88 | 18425 |  |  |  |  | 11750 | my $col  = shift; | 
| 89 | 18425 | 100 |  |  |  | 16620 | if ( defined $col ) { | 
| 90 | 8324 |  |  |  |  | 6689 | $self->{col} = $col; | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  | else { | 
| 93 | 10101 |  |  |  |  | 26860 | return $self->{col}; | 
| 94 |  |  |  |  |  |  | } | 
| 95 |  |  |  |  |  |  | } | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | sub ast { | 
| 98 | 108 |  |  | 108 | 0 | 119 | my $self = shift; | 
| 99 | 108 |  |  |  |  | 710 | return $self->{ast}; | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | sub peekc { | 
| 103 | 26080 |  |  | 26080 | 0 | 16425 | my $self = shift; | 
| 104 | 26080 |  |  |  |  | 23745 | my $fh   = $self->filehandler(); | 
| 105 | 26080 | 50 |  |  |  | 30518 | die "file handler is un-defined" if ( !defined $fh ); | 
| 106 | 26080 |  |  |  |  | 16302 | my $c = undef; | 
| 107 | 26080 | 100 |  |  |  | 57326 | if ( !eof($fh) ) { | 
| 108 | 25972 |  |  |  |  | 22487 | $c = getc($fh); | 
| 109 | 25972 |  |  |  |  | 26366 | seek( $fh, -1, 1 ); | 
| 110 |  |  |  |  |  |  | } | 
| 111 | 26080 |  |  |  |  | 29061 | return $c; | 
| 112 |  |  |  |  |  |  | } | 
| 113 |  |  |  |  |  |  |  | 
| 114 |  |  |  |  |  |  | sub readc { | 
| 115 | 8216 |  |  | 8216 | 0 | 5196 | my $self = shift; | 
| 116 | 8216 |  |  |  |  | 7825 | my $fh   = $self->filehandler(); | 
| 117 | 8216 |  |  |  |  | 8581 | my $c    = $self->peekc(); | 
| 118 | 8216 | 50 |  |  |  | 10556 | if ( defined $c ) { | 
| 119 | 8216 | 100 |  |  |  | 8537 | if ( $c eq "\n" ) { | 
| 120 | 293 |  |  |  |  | 374 | $self->line( 1 + $self->line() ); | 
| 121 | 293 |  |  |  |  | 337 | $self->col(1); | 
| 122 |  |  |  |  |  |  | } | 
| 123 |  |  |  |  |  |  | else { | 
| 124 | 7923 |  |  |  |  | 8541 | $self->col( 1 + $self->col() ); | 
| 125 |  |  |  |  |  |  | } | 
| 126 | 8216 |  |  |  |  | 8230 | seek( $fh, 1, 1 ); | 
| 127 |  |  |  |  |  |  | } | 
| 128 | 8216 |  |  |  |  | 17741 | return $c; | 
| 129 |  |  |  |  |  |  | } | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | sub consume { | 
| 132 | 7796 |  |  | 7796 | 0 | 5482 | my $self   = shift; | 
| 133 | 7796 |  |  |  |  | 5221 | my $offset = shift; | 
| 134 | 7796 |  |  |  |  | 10818 | for ( my $i = 0 ; $i < $offset ; $i++ ) { | 
| 135 | 7796 |  |  |  |  | 7563 | $self->readc(); | 
| 136 |  |  |  |  |  |  | } | 
| 137 |  |  |  |  |  |  | } | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | sub skip_blanks { | 
| 140 | 6387 |  |  | 6387 | 0 | 4806 | my $self = shift; | 
| 141 | 6387 |  |  |  |  | 4282 | my $c    = undef; | 
| 142 | 6387 |  |  |  |  | 4534 | do { | 
| 143 | 8389 |  |  |  |  | 8120 | $c = $self->peekc(); | 
| 144 | 8389 | 100 |  |  |  | 9132 | if ( defined $c ) { | 
| 145 | 8281 | 100 |  |  |  | 16655 | if ( $c eq ";" ) { | 
|  |  | 100 |  |  |  |  |  | 
| 146 | 22 |  |  |  |  | 45 | $self->consume(1); | 
| 147 | 22 |  |  |  |  | 50 | $self->comment(); | 
| 148 |  |  |  |  |  |  | } | 
| 149 |  |  |  |  |  |  | elsif ( $c =~ /\s/ ) { | 
| 150 | 1980 |  |  |  |  | 2281 | $self->consume(1); | 
| 151 |  |  |  |  |  |  | } | 
| 152 |  |  |  |  |  |  | else { | 
| 153 | 6279 |  |  |  |  | 9957 | $c = undef; | 
| 154 |  |  |  |  |  |  | } | 
| 155 |  |  |  |  |  |  | } | 
| 156 |  |  |  |  |  |  | else { | 
| 157 | 108 |  |  |  |  | 186 | $c = undef; | 
| 158 |  |  |  |  |  |  | } | 
| 159 |  |  |  |  |  |  | } until !defined $c; | 
| 160 |  |  |  |  |  |  | } | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | sub parse { | 
| 163 | 108 |  |  | 108 | 0 | 118 | my $self        = shift; | 
| 164 | 108 |  |  |  |  | 110 | my $file_or_str = shift; | 
| 165 | 108 |  |  |  |  | 116 | my $mode        = shift; | 
| 166 | 108 | 100 |  |  |  | 269 | $mode = "string" if !defined $mode; | 
| 167 | 108 |  |  |  |  | 150 | my $fh = undef; | 
| 168 | 108 | 100 |  |  |  | 224 | if ( $mode eq "string" ) { | 
| 169 | 102 | 50 |  | 3 |  | 1468 | open $fh, "<", \$file_or_str or die "cannot read string $file_or_str"; | 
|  | 3 |  |  |  |  | 13 |  | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 15 |  | 
| 170 |  |  |  |  |  |  | } | 
| 171 |  |  |  |  |  |  | else { | 
| 172 | 6 | 50 |  |  |  | 285 | open $fh, "<", $file_or_str or die "cannot open file $file_or_str"; | 
| 173 |  |  |  |  |  |  | } | 
| 174 | 108 |  |  |  |  | 2175 | $self->filehandler($fh); | 
| 175 | 108 |  |  |  |  | 199 | $self->filename($file_or_str); | 
| 176 | 108 |  |  |  |  | 201 | $self->line(1); | 
| 177 | 108 |  |  |  |  | 181 | $self->col(1); | 
| 178 | 108 |  |  |  |  | 3356 | my $ast = Language::LispPerl::Seq->new(); | 
| 179 | 108 |  |  |  |  | 160 | do { | 
| 180 | 157 |  |  |  |  | 320 | $self->skip_blanks(); | 
| 181 | 157 |  |  |  |  | 283 | my $r = $self->lex(); | 
| 182 | 157 | 50 |  |  |  | 602 | $ast->append($r) if defined $r; | 
| 183 |  |  |  |  |  |  | } until eof($fh); | 
| 184 | 108 |  |  |  |  | 144 | $self->{ast} = $ast; | 
| 185 | 108 | 100 |  |  |  | 644 | close $fh if $mode ne "string"; | 
| 186 |  |  |  |  |  |  | } | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | sub read_file { | 
| 189 | 6 |  |  | 6 | 0 | 19 | my $self = shift; | 
| 190 | 6 |  |  |  |  | 7 | my $file = shift; | 
| 191 | 6 |  |  |  |  | 21 | $self->parse( $file, "file" ); | 
| 192 |  |  |  |  |  |  | } | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | sub read_string { | 
| 195 | 102 |  |  | 102 | 0 | 109 | my $self = shift; | 
| 196 | 102 |  |  |  |  | 110 | my $str  = shift; | 
| 197 | 102 |  |  |  |  | 235 | $self->parse($str); | 
| 198 |  |  |  |  |  |  | } | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | sub show { | 
| 201 | 0 |  |  | 0 | 0 | 0 | my $self   = shift; | 
| 202 | 0 |  |  |  |  | 0 | my $indent = shift; | 
| 203 | 0 | 0 |  |  |  | 0 | $indent = "" if !defined $indent; | 
| 204 | 0 |  |  |  |  | 0 | $self->{ast}->show($indent); | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | sub lex { | 
| 208 | 2241 |  |  | 2241 | 0 | 1779 | my $self = shift; | 
| 209 | 2241 |  |  |  |  | 2370 | my $c    = $self->peekc(); | 
| 210 | 2241 | 50 |  |  |  | 3260 | if ( defined $c ) { | 
| 211 | 2241 | 100 | 100 |  |  | 15987 | if ( $c eq '(' ) { | 
|  |  | 100 | 66 |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 212 | 430 |  |  |  |  | 892 | return $self->seq( "list", "(", ")" ); | 
| 213 |  |  |  |  |  |  | } | 
| 214 |  |  |  |  |  |  | elsif ( $c eq '"' ) { | 
| 215 | 76 |  |  |  |  | 161 | return $self->string(); | 
| 216 |  |  |  |  |  |  | } | 
| 217 |  |  |  |  |  |  | elsif ( $c =~ /\d/ ) { | 
| 218 | 93 |  |  |  |  | 190 | return $self->number(); | 
| 219 |  |  |  |  |  |  | } | 
| 220 |  |  |  |  |  |  | elsif ( $c eq '[' ) { | 
| 221 | 92 |  |  |  |  | 228 | return $self->seq( "vector", "[", "]" ); | 
| 222 |  |  |  |  |  |  | } | 
| 223 |  |  |  |  |  |  | elsif ( $c eq '{' ) { | 
| 224 | 14 |  |  |  |  | 31 | return $self->seq( "map", "{", "}" ); | 
| 225 |  |  |  |  |  |  | } | 
| 226 |  |  |  |  |  |  | elsif ( $c eq '#' ) { | 
| 227 | 25 |  |  |  |  | 48 | $self->consume(1); | 
| 228 | 25 |  |  |  |  | 60 | return $self->dispatch(); | 
| 229 |  |  |  |  |  |  | } | 
| 230 |  |  |  |  |  |  | elsif ( $c eq '^' ) { | 
| 231 | 11 |  |  |  |  | 24 | $self->consume(1); | 
| 232 | 11 | 50 |  |  |  | 22 | $self->error("meta should be a map") if $self->peekc() ne "{"; | 
| 233 | 11 |  |  |  |  | 24 | my $md = $self->lex(); | 
| 234 | 11 |  |  |  |  | 301 | $md->type("meta"); | 
| 235 | 11 |  |  |  |  | 18 | return $md; | 
| 236 |  |  |  |  |  |  | } | 
| 237 |  |  |  |  |  |  | elsif ( $c eq ':' ) { | 
| 238 | 12 |  |  |  |  | 22 | $self->consume(1); | 
| 239 | 12 |  |  |  |  | 22 | my $k = $self->symbol(); | 
| 240 | 12 |  |  |  |  | 315 | $k->type("keyword"); | 
| 241 | 12 |  |  |  |  | 14 | return $k; | 
| 242 |  |  |  |  |  |  | } | 
| 243 |  |  |  |  |  |  | elsif ( $c eq "'" ) { | 
| 244 | 0 |  |  |  |  | 0 | $self->consume(1); | 
| 245 | 0 |  |  |  |  | 0 | my $q = $self->lex(); | 
| 246 | 0 |  |  |  |  | 0 | return Language::LispPerl::Atom->new({type =>  "quotation", value => $q }); | 
| 247 |  |  |  |  |  |  | } | 
| 248 |  |  |  |  |  |  | elsif ( $c eq "`" ) { | 
| 249 | 37 |  |  |  |  | 72 | $self->consume(1); | 
| 250 | 37 |  |  |  |  | 65 | my $sq = $self->lex(); | 
| 251 | 37 |  |  |  |  | 1011 | return Language::LispPerl::Atom->new({ type => "syntaxquotation", value => $sq }); | 
| 252 |  |  |  |  |  |  | } | 
| 253 |  |  |  |  |  |  | elsif ( $c eq "~" ) { | 
| 254 | 52 |  |  |  |  | 85 | $self->consume(1); | 
| 255 | 52 |  |  |  |  | 74 | my $dq = $self->symbol(); | 
| 256 | 52 |  |  |  |  | 1486 | $dq->type("dequotation"); | 
| 257 | 52 |  |  |  |  | 133 | return $dq; | 
| 258 |  |  |  |  |  |  |  | 
| 259 |  |  |  |  |  |  | #} elsif($c eq "@") { | 
| 260 |  |  |  |  |  |  | #  $self->consume(1); | 
| 261 |  |  |  |  |  |  | #  my $dr = $self->symbol(); | 
| 262 |  |  |  |  |  |  | #$dr->type("deref"); | 
| 263 |  |  |  |  |  |  | #return $dr; | 
| 264 |  |  |  |  |  |  | } | 
| 265 |  |  |  |  |  |  | elsif ( $c eq ";" ) { | 
| 266 | 0 |  |  |  |  | 0 | $self->consume(1); | 
| 267 | 0 |  |  |  |  | 0 | $self->comment(); | 
| 268 | 0 |  |  |  |  | 0 | return undef; | 
| 269 |  |  |  |  |  |  | } | 
| 270 |  |  |  |  |  |  | elsif ( ( $c eq ')' or $c eq ']' or $c eq '}' ) | 
| 271 |  |  |  |  |  |  | and $self->{nest} == 0 ) | 
| 272 |  |  |  |  |  |  | { | 
| 273 | 0 |  |  |  |  | 0 | $self->error( "unexpected " . $c ); | 
| 274 |  |  |  |  |  |  | } | 
| 275 |  |  |  |  |  |  | else { | 
| 276 | 1399 |  |  |  |  | 1951 | return $self->symbol(); | 
| 277 |  |  |  |  |  |  | } | 
| 278 |  |  |  |  |  |  | } | 
| 279 | 0 |  |  |  |  | 0 | return undef; | 
| 280 |  |  |  |  |  |  | } | 
| 281 |  |  |  |  |  |  |  | 
| 282 |  |  |  |  |  |  | sub dispatch { | 
| 283 | 25 |  |  | 25 | 0 | 27 | my $self = shift; | 
| 284 | 25 |  |  |  |  | 40 | my $c    = $self->peekc(); | 
| 285 | 25 | 50 |  |  |  | 51 | if ( defined $c ) { | 
| 286 | 25 | 100 |  |  |  | 65 | if ( $c eq ":" ) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 287 | 15 |  |  |  |  | 27 | $self->consume(1); | 
| 288 | 15 |  |  |  |  | 50 | return Language::LispPerl::Atom->new({ type => "accessor", value => $self->lex() }); | 
| 289 |  |  |  |  |  |  | } | 
| 290 |  |  |  |  |  |  | elsif ( $c eq "!" ) { | 
| 291 | 0 |  |  |  |  | 0 | $self->consume(1); | 
| 292 | 0 |  |  |  |  | 0 | return Language::LispPerl::Atom->new({ type => "sender", value => $self->lex() }); | 
| 293 |  |  |  |  |  |  | } | 
| 294 |  |  |  |  |  |  | elsif ( $c eq '[' ) { | 
| 295 | 10 |  |  |  |  | 18 | return $self->seq( "xml", "[", "]" ); | 
| 296 |  |  |  |  |  |  | } | 
| 297 |  |  |  |  |  |  | else { | 
| 298 | 0 |  |  |  |  | 0 | $self->error("unsupport syntax for disptacher"); | 
| 299 |  |  |  |  |  |  | } | 
| 300 |  |  |  |  |  |  | } | 
| 301 | 0 |  |  |  |  | 0 | return undef; | 
| 302 |  |  |  |  |  |  | } | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | sub comment { | 
| 305 | 22 |  |  | 22 | 0 | 28 | my $self = shift; | 
| 306 | 22 |  |  |  |  | 28 | my $c    = undef; | 
| 307 | 22 |  |  |  |  | 21 | do { | 
| 308 | 420 |  |  |  |  | 401 | $c = $self->readc(); | 
| 309 | 420 | 100 | 66 |  |  | 1424 | if ( defined $c and $c eq "\n" ) { | 
| 310 | 22 |  |  |  |  | 45 | $c = undef; | 
| 311 |  |  |  |  |  |  | } | 
| 312 |  |  |  |  |  |  | } until !defined $c; | 
| 313 | 22 |  |  |  |  | 49 | $self->skip_blanks(); | 
| 314 |  |  |  |  |  |  |  | 
| 315 | 22 |  |  |  |  | 31 | return undef; | 
| 316 |  |  |  |  |  |  | } | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  | sub string { | 
| 319 | 76 |  |  | 76 | 0 | 76 | my $self = shift; | 
| 320 | 76 |  |  |  |  | 66 | my $c    = undef; | 
| 321 | 76 |  |  |  |  | 2190 | my $s    = Language::LispPerl::Atom->new({ type => "string" }); | 
| 322 |  |  |  |  |  |  | $s->{pos} = { | 
| 323 | 76 |  |  |  |  | 177 | filename => $self->filename(), | 
| 324 |  |  |  |  |  |  | line     => $self->line(), | 
| 325 |  |  |  |  |  |  | col      => $self->col() | 
| 326 |  |  |  |  |  |  | }; | 
| 327 | 76 |  |  |  |  | 151 | $self->consume(1); | 
| 328 | 76 |  |  |  |  | 69 | do { | 
| 329 | 458 |  |  |  |  | 450 | $c = $self->peekc(); | 
| 330 | 458 | 50 |  |  |  | 603 | if ( defined $c ) { | 
| 331 | 458 | 100 |  |  |  | 703 | if ( $c eq "\\" ) { | 
|  |  | 100 |  |  |  |  |  | 
| 332 | 1 |  |  |  |  | 5 | $self->consume(1); | 
| 333 | 1 |  |  |  |  | 2 | my $nc = $self->peekc(); | 
| 334 | 1 | 50 |  |  |  | 4 | $self->error("unexpected eof") if !defined $nc; | 
| 335 | 1 |  |  |  |  | 3 | $self->consume(1); | 
| 336 | 1 |  |  |  |  | 2 | my $rc = $nc; | 
| 337 | 1 | 50 |  |  |  | 13 | if ( $nc eq "a" ) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 338 | 0 |  |  |  |  | 0 | $rc = "\a"; | 
| 339 |  |  |  |  |  |  | } | 
| 340 |  |  |  |  |  |  | elsif ( $nc eq "b" ) { | 
| 341 | 0 |  |  |  |  | 0 | $rc = "\b"; | 
| 342 |  |  |  |  |  |  | } | 
| 343 |  |  |  |  |  |  | elsif ( $nc eq "e" ) { | 
| 344 | 0 |  |  |  |  | 0 | $rc = "\e"; | 
| 345 |  |  |  |  |  |  | } | 
| 346 |  |  |  |  |  |  | elsif ( $nc eq "f" ) { | 
| 347 | 0 |  |  |  |  | 0 | $rc = "\f"; | 
| 348 |  |  |  |  |  |  | } | 
| 349 |  |  |  |  |  |  | elsif ( $nc eq "n" ) { | 
| 350 | 0 |  |  |  |  | 0 | $rc = "\n"; | 
| 351 |  |  |  |  |  |  | } | 
| 352 |  |  |  |  |  |  | elsif ( $nc eq "r" ) { | 
| 353 | 0 |  |  |  |  | 0 | $rc = "\r"; | 
| 354 |  |  |  |  |  |  | } | 
| 355 |  |  |  |  |  |  | elsif ( $nc eq "t" ) { | 
| 356 | 0 |  |  |  |  | 0 | $rc = "\t"; | 
| 357 |  |  |  |  |  |  | } | 
| 358 | 1 |  |  |  |  | 3 | $s->{value} .= $rc; | 
| 359 |  |  |  |  |  |  | } | 
| 360 |  |  |  |  |  |  | elsif ( $c ne '"' ) { | 
| 361 | 381 |  |  |  |  | 348 | $s->{value} .= $c; | 
| 362 | 381 |  |  |  |  | 401 | $self->consume(1); | 
| 363 |  |  |  |  |  |  | } | 
| 364 |  |  |  |  |  |  | else { | 
| 365 | 76 |  |  |  |  | 115 | $c = undef; | 
| 366 |  |  |  |  |  |  | } | 
| 367 |  |  |  |  |  |  | } | 
| 368 |  |  |  |  |  |  | } until !defined $c; | 
| 369 | 76 |  |  |  |  | 91 | $c = $self->peekc(); | 
| 370 | 76 | 50 | 33 |  |  | 259 | if ( defined $c and $c eq '"' ) { | 
| 371 | 76 |  |  |  |  | 94 | $self->consume(1); | 
| 372 |  |  |  |  |  |  | } | 
| 373 |  |  |  |  |  |  | else { | 
| 374 | 0 |  |  |  |  | 0 | $self->error("expect \""); | 
| 375 |  |  |  |  |  |  | } | 
| 376 | 76 |  |  |  |  | 108 | $self->skip_blanks(); | 
| 377 | 76 |  |  |  |  | 107 | return $s; | 
| 378 |  |  |  |  |  |  | } | 
| 379 |  |  |  |  |  |  |  | 
| 380 |  |  |  |  |  |  | sub number { | 
| 381 | 93 |  |  | 93 | 0 | 101 | my $self = shift; | 
| 382 | 93 |  |  |  |  | 81 | my $c    = undef; | 
| 383 | 93 |  |  |  |  | 2633 | my $n    = Language::LispPerl::Atom->new({ type => "number" }); | 
| 384 |  |  |  |  |  |  | $n->{pos} = { | 
| 385 | 93 |  |  |  |  | 215 | filename => $self->filename(), | 
| 386 |  |  |  |  |  |  | line     => $self->line(), | 
| 387 |  |  |  |  |  |  | col      => $self->col() | 
| 388 |  |  |  |  |  |  | }; | 
| 389 | 93 |  |  |  |  | 133 | do { | 
| 390 | 189 |  |  |  |  | 205 | $c = $self->peekc(); | 
| 391 | 189 | 100 | 66 |  |  | 2074 | if (    defined $c | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 392 |  |  |  |  |  |  | and $c =~ /\S/ | 
| 393 |  |  |  |  |  |  | and $c ne ";" | 
| 394 |  |  |  |  |  |  | and $c ne '(' | 
| 395 |  |  |  |  |  |  | and $c ne ')' | 
| 396 |  |  |  |  |  |  | and $c ne '[' | 
| 397 |  |  |  |  |  |  | and $c ne ']' | 
| 398 |  |  |  |  |  |  | and $c ne '{' | 
| 399 |  |  |  |  |  |  | and $c ne '}' ) | 
| 400 |  |  |  |  |  |  | { | 
| 401 | 96 | 50 |  |  |  | 186 | if ( $c =~ /[\+\-\d\.xXabcdefABCDEF\/\_]/ ) { | 
| 402 | 96 |  |  |  |  | 145 | $self->consume(1); | 
| 403 | 96 |  |  |  |  | 258 | $n->{value} .= $c; | 
| 404 |  |  |  |  |  |  | } | 
| 405 |  |  |  |  |  |  | else { | 
| 406 | 0 |  |  |  |  | 0 | $self->error( "unexpect letter " . $c . " for number" ); | 
| 407 |  |  |  |  |  |  | } | 
| 408 |  |  |  |  |  |  | } | 
| 409 |  |  |  |  |  |  | else { | 
| 410 | 93 |  |  |  |  | 177 | $c = undef; | 
| 411 |  |  |  |  |  |  | } | 
| 412 |  |  |  |  |  |  | } until !defined $c; | 
| 413 |  |  |  |  |  |  | local $SIG{__WARN__} = sub { | 
| 414 | 0 |  |  | 0 |  | 0 | $n->error( "invild number literal " . $n->{value} ); | 
| 415 | 93 |  |  |  |  | 611 | }; | 
| 416 | 93 |  |  |  |  | 263 | $n->{value} = 0 + $n->{value}; | 
| 417 | 93 |  |  |  |  | 366 | delete $SIG{__WARN__}; | 
| 418 | 93 |  |  |  |  | 142 | $self->skip_blanks(); | 
| 419 | 93 |  |  |  |  | 426 | return $n; | 
| 420 |  |  |  |  |  |  | } | 
| 421 |  |  |  |  |  |  |  | 
| 422 |  |  |  |  |  |  | sub symbol { | 
| 423 | 1463 |  |  | 1463 | 0 | 1086 | my $self = shift; | 
| 424 | 1463 |  |  |  |  | 1094 | my $c    = undef; | 
| 425 | 1463 |  |  |  |  | 40007 | my $sym  = Language::LispPerl::Atom->new({ type => "symbol" }); | 
| 426 | 1463 |  |  |  |  | 2567 | $self->skip_blanks(); | 
| 427 |  |  |  |  |  |  | $sym->{pos} = { | 
| 428 | 1463 |  |  |  |  | 1918 | filename => $self->filename(), | 
| 429 |  |  |  |  |  |  | line     => $self->line(), | 
| 430 |  |  |  |  |  |  | col      => $self->col() | 
| 431 |  |  |  |  |  |  | }; | 
| 432 | 1463 |  |  |  |  | 1744 | do { | 
| 433 | 5382 |  |  |  |  | 5559 | $c = $self->peekc(); | 
| 434 | 5382 | 50 |  |  |  | 7128 | if ( defined $c ) { | 
| 435 | 5382 | 100 | 66 |  |  | 51684 | if (    $c =~ /\S/ | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 436 |  |  |  |  |  |  | and $c ne ';' | 
| 437 |  |  |  |  |  |  | and $c ne '(' | 
| 438 |  |  |  |  |  |  | and $c ne ')' | 
| 439 |  |  |  |  |  |  | and $c ne '[' | 
| 440 |  |  |  |  |  |  | and $c ne ']' | 
| 441 |  |  |  |  |  |  | and $c ne '{' | 
| 442 |  |  |  |  |  |  | and $c ne '}' ) | 
| 443 |  |  |  |  |  |  | { | 
| 444 | 3919 | 50 |  |  |  | 5645 | $self->error( "unexpected letter " . $c . " for symbol" ) | 
| 445 |  |  |  |  |  |  | if $c =~ /[^0-9a-zA-Z_!&\?\*\/\.\+\|=%\$<>#@\:\-\\]/; | 
| 446 | 3919 |  |  |  |  | 3761 | $sym->{value} .= $c; | 
| 447 | 3919 |  |  |  |  | 4211 | $self->consume(1); | 
| 448 |  |  |  |  |  |  | } | 
| 449 |  |  |  |  |  |  | else { | 
| 450 | 1463 |  |  |  |  | 2309 | $c = undef; | 
| 451 |  |  |  |  |  |  | } | 
| 452 |  |  |  |  |  |  | } | 
| 453 |  |  |  |  |  |  | } until !defined $c; | 
| 454 | 1463 |  |  |  |  | 1712 | $self->skip_blanks(); | 
| 455 | 1463 | 100 |  |  |  | 1951 | if ( $sym->{value} eq "" ) { | 
| 456 | 546 |  |  |  |  | 14660 | return undef; | 
| 457 |  |  |  |  |  |  | } | 
| 458 |  |  |  |  |  |  | else { | 
| 459 | 917 |  |  |  |  | 1414 | return $sym; | 
| 460 |  |  |  |  |  |  | } | 
| 461 |  |  |  |  |  |  | } | 
| 462 |  |  |  |  |  |  |  | 
| 463 |  |  |  |  |  |  | sub seq { | 
| 464 | 546 |  |  | 546 | 0 | 452 | my $self  = shift; | 
| 465 | 546 |  |  |  |  | 482 | my $type  = shift; | 
| 466 | 546 |  |  |  |  | 449 | my $begin = shift; | 
| 467 | 546 |  |  |  |  | 445 | my $end   = shift; | 
| 468 | 546 | 50 |  |  |  | 813 | $type  = "list" if !defined $type; | 
| 469 | 546 | 50 |  |  |  | 690 | $begin = "("    if !defined $begin; | 
| 470 | 546 | 50 |  |  |  | 660 | $end   = ")"    if !defined $end; | 
| 471 | 546 |  |  |  |  | 413 | my $e = undef; | 
| 472 | 546 |  |  |  |  | 656 | my $c = $self->peekc(); | 
| 473 |  |  |  |  |  |  |  | 
| 474 | 546 | 50 | 33 |  |  | 1679 | if ( defined $c and $c eq $begin ) { | 
| 475 | 546 |  |  |  |  | 706 | $self->consume(1); | 
| 476 |  |  |  |  |  |  | } | 
| 477 |  |  |  |  |  |  | else { | 
| 478 | 0 |  |  |  |  | 0 | $self->error( "expect " . $begin ); | 
| 479 |  |  |  |  |  |  | } | 
| 480 | 546 |  |  |  |  | 641 | $self->skip_blanks(); | 
| 481 | 546 |  |  |  |  | 15330 | my $seq = Language::LispPerl::Seq->new({ type => $type }); | 
| 482 | 546 |  |  |  |  | 1171 | $seq->pos({ | 
| 483 |  |  |  |  |  |  | filename => $self->filename(), | 
| 484 |  |  |  |  |  |  | line     => $self->line(), | 
| 485 |  |  |  |  |  |  | col      => $self->col() | 
| 486 |  |  |  |  |  |  | }); | 
| 487 | 546 |  |  |  |  | 595 | $self->{nest} += 1; | 
| 488 | 546 |  |  |  |  | 409 | do { | 
| 489 | 2021 |  |  |  |  | 3038 | $e = $self->lex(); | 
| 490 | 2021 |  |  |  |  | 2358 | $self->skip_blanks(); | 
| 491 | 2021 | 100 |  |  |  | 5578 | $seq->append($e) if defined $e; | 
| 492 |  |  |  |  |  |  | } until !defined $e; | 
| 493 | 546 |  |  |  |  | 639 | $c = $self->peekc(); | 
| 494 | 546 | 50 | 33 |  |  | 1746 | if ( defined $c and $c eq $end ) { | 
| 495 | 546 |  |  |  |  | 676 | $self->consume(1); | 
| 496 | 546 |  |  |  |  | 653 | $self->{nest} -= 1; | 
| 497 |  |  |  |  |  |  | } | 
| 498 |  |  |  |  |  |  | else { | 
| 499 | 0 |  |  |  |  | 0 | $self->error( "expect " . $end ); | 
| 500 |  |  |  |  |  |  | } | 
| 501 | 546 |  |  |  |  | 605 | $self->skip_blanks(); | 
| 502 | 546 |  |  |  |  | 1048 | return $seq; | 
| 503 |  |  |  |  |  |  | } | 
| 504 |  |  |  |  |  |  |  | 
| 505 |  |  |  |  |  |  | sub error { | 
| 506 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 507 | 0 |  |  |  |  | 0 | my $msg  = shift; | 
| 508 | 0 |  |  |  |  | 0 | $msg .= " @[file: " . $self->filename(); | 
| 509 | 0 |  |  |  |  | 0 | $msg .= "; line: " . $self->line(); | 
| 510 | 0 |  |  |  |  | 0 | $msg .= "; col: " . $self->col() . "]"; | 
| 511 | 0 |  |  |  |  | 0 | Language::LispPerl::Logger::error($msg); | 
| 512 |  |  |  |  |  |  | } | 
| 513 |  |  |  |  |  |  | 1; |