root/branches/boomer/extlib/JSON/Parser.pm @ 1098

Revision 1098, 4.5 kB (checked in by hachi, 2 years ago)

Branching for boomer from release-19, rev 62318

Line 
1package JSON::Parser;
2
3#
4# Perl implementaion of json.js
5#  http://www.crockford.com/JSON/json.js
6#
7
8use vars qw($VERSION);
9use strict;
10
11$VERSION     = 0.932;
12
13my %escapes = ( #  by Jeremy Muhlich <jmuhlich [at] bitflood.org>
14  b    => "\x8",
15  t    => "\x9",
16  n    => "\xA",
17  f    => "\xC",
18  r    => "\xD",
19#  '/'  => '/',
20  '\\' => '\\',
21);
22
23
24sub new {
25        my $class = shift;
26        my $self  = {};
27        bless $self,$class;
28}
29
30
31*jsonToObj = \&parse;
32
33
34{ # PARSE
35
36        my $text;
37        my $at;
38        my $ch;
39        my $len;
40
41        sub parse {
42                my $self = shift;
43                $text = shift;
44                $at   = 0;
45                $ch   = '';
46                $len  = length $text;
47                value();
48        }
49
50
51        sub next_chr {
52                return $ch = undef if($at >= $len);
53                $ch = substr($text, $at++, 1);
54        }
55
56
57        sub value {
58                white();
59                return object() if($ch eq '{');
60                return array()  if($ch eq '[');
61                return string() if($ch eq '"');
62                return number() if($ch eq '-');
63                return $ch =~ /\d/ ? number() : word();
64        }
65
66
67        sub string {
68                my ($i,$s,$t,$u);
69                $s = '';
70
71                if($ch eq '"'){
72                        OUTER: while( defined(next_chr()) ){
73                                if($ch eq '"'){
74                                        next_chr();
75                                        return $s;
76                                }
77                                elsif($ch eq '\\'){
78                                        next_chr();
79                                        if(exists $escapes{$ch}){
80                                                $s .= $escapes{$ch};
81                                        }
82                                        elsif($ch eq 'u'){
83                                                my $u = '';
84                                                for(1..4){
85                                                        $ch = next_chr();
86                                                        last OUTER if($ch !~ /[\da-fA-F]/);
87                                                        $u .= $ch;
88                                                }
89                                                $u =~ s/^00// or error("Bad string");
90                                                $s .= pack('H2',$u);
91                                        }
92                                        else{
93                                                $s .= $ch;
94                                        }
95                                }
96                                else{
97                                        $s .= $ch;
98                                }
99                        }
100                }
101
102                error("Bad string");
103        }
104
105
106        sub white {
107                while( defined $ch  ){
108                        if($ch le ' '){
109                                next_chr();
110                        }
111                        elsif($ch eq '/'){
112                                next_chr();
113                                if($ch eq '/'){
114                                        1 while(defined(next_chr()) and $ch ne "\n" and $ch ne "\r");
115                                }
116                                elsif($ch eq '*'){
117                                        next_chr();
118                                        while(1){
119                                                if(defined $ch){
120                                                        if($ch eq '*'){
121                                                                if(defined(next_chr()) and $ch eq '/'){
122                                                                        next_chr();
123                                                                        last;
124                                                                }
125                                                        }
126                                                        else{
127                                                                next_chr();
128                                                        }
129                                                }
130                                                else{
131                                                        error("Unterminated comment");
132                                                }
133                                        }
134                                        next;
135                                }
136                                else{
137                                        error("Syntax error (whitespace)");
138                                }
139                        }
140                        else{
141                                last;
142                        }
143                }
144        }
145
146
147        sub object {
148                my $o = {};
149                my $k;
150
151                if($ch eq '{'){
152                        next_chr();
153                        white();
154                        if($ch eq '}'){
155                                next_chr();
156                                return $o;
157                        }
158                        while(defined $ch){
159                                $k = string();
160                                white();
161
162                                if($ch ne ':'){
163                                        last;
164                                }
165
166                                next_chr();
167                                $o->{$k} = value();
168                                white();
169
170                                if($ch eq '}'){
171                                        next_chr();
172                                        return $o;
173                                }
174                                elsif($ch ne ','){
175                                        last;
176                                }
177                                next_chr();
178                                white();
179                        }
180
181                        error("Bad object");
182                }
183        }
184
185
186        sub word {
187                my $word =  substr($text,$at-1,4);
188
189                if($word eq 'true'){
190                        $at += 3;
191                        next_chr;
192                        return bless {value => 'true'}, 'JSON::NotString'
193                }
194                elsif($word eq 'null'){
195                        $at += 3;
196                        next_chr;
197                        return bless {value => undef}, 'JSON::NotString'
198                }
199                elsif($word eq 'fals'){
200                        $at += 3;
201                        if(substr($text,$at,1) eq 'e'){
202                                $at++;
203                                next_chr;
204                                return bless {value => 'false'}, 'JSON::NotString'
205                        }
206                }
207
208                error("Syntax error (word)");
209        }
210
211
212        sub number {
213                my $n    = '';
214                my $v;
215
216                if($ch eq '0'){
217                        my $peek = substr($text,$at,1);
218                        my $hex  = $peek =~ /[xX]/;
219
220                        if($hex){
221                                ($n) = ( substr($text, $at+1) =~ /^([0-9a-fA-F]+)/);
222                        }
223                        else{
224                                ($n) = ( substr($text, $at) =~ /^([0-7]+)/);
225                        }
226
227                        if(defined $n and length($n)){
228                                $at += length($n) + $hex;
229                                next_chr;
230                                return $hex ? hex($n) : oct($n);
231                        }
232                }
233
234                if($ch eq '-'){
235                        $n = '-';
236                        next_chr;
237                }
238
239                while($ch =~ /\d/){
240                        $n .= $ch;
241                        next_chr;
242                }
243
244                if($ch eq '.'){
245                        $n .= '.';
246                        while(defined(next_chr) and $ch =~ /\d/){
247                                $n .= $ch;
248                        }
249                }
250
251                $v .= $n;
252
253                return $v;
254        }
255
256
257        sub array {
258                my $a  = [];
259
260                if($ch eq '['){
261                        next_chr();
262                        white();
263                        if($ch eq ']'){
264                                next_chr();
265                                return $a;
266                        }
267                        while(defined($ch)){
268                                push @$a, value();
269                                white();
270                                if($ch eq ']'){
271                                        next_chr();
272                                        return $a;
273                                }
274                                elsif($ch ne ','){
275                                        last;
276                                }
277                                next_chr();
278                                white();
279                        }
280                }
281
282                error("Bad array");
283        }
284
285
286        sub error {
287                my $error = shift;
288                die "$error at $at in $text.";
289        }
290
291} # PARSE
292
293
294
295package JSON::NotString;
296
297use overload (
298        '""'   => sub { $_[0]->{value} },
299        'bool' => sub {
300                  ! defined $_[0]->{value}  ? undef
301                : $_[0]->{value} eq 'false' ? 0 : 1;
302        },
303);
304
3051;
306
307__END__
308
309=head1 SEE ALSO
310
311L<http://www.crockford.com/JSON/index.html>
312
313This module is an implementation of L<http://www.crockford.com/JSON/json.js>.
314
315
316=head1 COPYRIGHT
317
318makamaka [at] donzoko.net
319
320This library is free software; you can redistribute it
321and/or modify it under the same terms as Perl itself.
322
323=cut
Note: See TracBrowser for help on using the browser.