4 my $x = shift || $class;
5 return bless \$x => __PACKAGE__;
7 use overload ( '""' => \&toString );
8 use overload ( '0+' => sub { $_[0]->toString } );
9 use overload ( '+' => sub { int($_[0]) + int($_[1]) } );
10 use overload ( '-' => sub { int($_[0]) - int($_[1]) } );
11 use overload ( '*' => sub { int($_[0]) * int($_[1]) } );
12 use overload ( '/' => sub { int($_[0]) / int($_[1]) } );
13 use overload ( '%' => sub { int($_[0]) % int($_[1]) } );
14 use overload ( '**' => sub { int($_[0]) ** int($_[1]) } );
15 use overload ( 'neg' => sub { -int($_[0]) } );
16 use overload ( '==' => sub { int($_[0]->toString) == int($_[1])} );
18 sub toString { defined($_[1]) ? ${$_[1]} : ${$_[0]} }
20 package JSON::bool::true;
21 sub new { return bless {} => __PACKAGE__ }
22 use overload ( '""' => \&toString );
23 use overload ( 'bool' => sub { 1 } );
24 use overload ( '0+' => sub { 1 } );
26 sub toString { 'true' }
28 package JSON::bool::false;
29 sub new { return bless {} => __PACKAGE__ }
30 use overload ( '""' => \&toString );
31 use overload ( 'bool' => sub { 0 } );
32 use overload ( '0+' => sub { 0 } );
34 sub toString { 'false' }
37 use vars qw/%_class_map/;
39 sub register_class_hint {
43 $_class_map{hints}{$args{hint}} = \%args;
44 $_class_map{classes}{$args{name}} = \%args;
53 -?\d+\.?\d* | # number literal
54 "(?:(?:\\[\"])|[^\"])*" | # string literal
55 (?:\/\*.+?\*\/) | # C comment
59 : | # object key-value sep
68 sub _json_hint_to_class {
72 return $_class_map{hints}{$hint}{name} if (exists $_class_map{hints}{$hint});
74 $type = 'hash' if ($type eq '}');
75 $type = 'array' if ($type eq ']');
77 JSON->register_class_hint(name => $hint, hint => $hint, type => $type);
86 s/(?<!\\)\$/\\\$/gmo; # fixup $ for later
87 s/(?<!\\)\@/\\\@/gmo; # fixup @ for later
88 s/(?<!\\)\%/\\\%/gmo; # fixup % for later
90 # Convert JSON Unicode...
91 s/\\u(\d{4})/chr(hex($1))/esog;
93 # handle class blessings
94 s/\/\*--\s*S\w*?\s+\S+\s*--\*\// bless(/sog;
95 s/(\]|\}|")\s*\/\*--\s*E\w*?\s+(\S+)\s*--\*\//$1 => _json_hint_to_class("$1", "$2")) /sog;
97 my $re = qr/((?<!\\)"(?>(?<=\\)"|[^"])*(?<!\\)")/;
99 my @strings = /$re/sog;
101 # Replace with code...
102 #s/"(?:(?:\\[\"])|[^\"])*"/ do{ \$t = '"'.shift(\@strings).'"'; eval \$t;} /sog;
103 s/$re/ eval shift(\@strings) /sog;
105 # Perlify hash notation
109 s/\b(-?\d+\.?\d*)\b/ JSON::number::new($1) /sog;
111 # Change javascript stuff to perl...
113 s/true/ bless( {}, "JSON::bool::true") /sog;
114 s/false/ bless( {}, "JSON::bool::false") /sog;
117 return eval '$ret = '.$_;
121 my ($class, $json) = @_;
123 if (!defined($json)) {
127 $json =~ s/(?<!\\)\$/\\\$/gmo; # fixup $ for later
128 $json =~ s/(?<!\\)\@/\\\@/gmo; # fixup @ for later
129 $json =~ s/(?<!\\)\%/\\\%/gmo; # fixup % for later
132 my $casting_depth = 0;
136 while (($json,$element) = _JSON_regex($json)) {
138 last unless ($element);
140 if ($element eq 'null') {
141 $output .= ' undef() ';
143 } elsif ($element =~ /^\/\*--\s*S\w*?\s+(\w+)\s*--\*\/$/) {
145 if (exists $_class_map{hints}{$hint}) {
146 $casts[$casting_depth] = $hint;
147 $output .= ' bless(';
150 } elsif ($element =~ /^\/\*/) {
152 } elsif ($element =~ /^\d/) {
153 $output .= "do { JSON::number::new($element) }";
155 } elsif ($element eq '{' or $element eq '[') {
157 } elsif ($element eq '}' or $element eq ']') {
159 my $hint = $casts[$casting_depth];
160 $casts[$casting_depth] = undef;
161 if (defined $hint and exists $_class_map{hints}{$hint}) {
162 $output .= $element . ',"'. $_class_map{hints}{$hint}{name} . '")';
165 } elsif ($element eq ':') {
168 } elsif ($element eq 'true') {
169 $output .= 'bless( {}, "JSON::bool::true")';
171 } elsif ($element eq 'false') {
172 $output .= 'bless( {}, "JSON::bool::false")';
183 my ($class, $perl) = @_;
186 if (!defined($perl)) {
188 } elsif (ref($perl) and ref($perl) =~ /^JSON/) {
190 } elsif ( ref($perl) && exists($_class_map{classes}{ref($perl)}) ) {
191 $output .= '/*--S '.$_class_map{classes}{ref($perl)}{hint}.'--*/';
192 if (lc($_class_map{classes}{ref($perl)}{type}) eq 'hash') {
194 $output .= perl2JSON(undef,\%hash);
195 } elsif (lc($_class_map{classes}{ref($perl)}{type}) eq 'array') {
197 $output .= perl2JSON(undef,\@array);
199 $output .= '/*--E '.$_class_map{classes}{ref($perl)}{hint}.'--*/';
200 } elsif (ref($perl) and ref($perl) =~ /HASH/) {
203 for my $key (sort keys %$perl) {
204 $output .= ',' if ($c);
206 $output .= perl2JSON(undef,$key).':'.perl2JSON(undef,$$perl{$key});
210 } elsif (ref($perl) and ref($perl) =~ /ARRAY/) {
213 for my $part (@$perl) {
214 $output .= ',' if ($c);
216 $output .= perl2JSON(undef,$part);
220 } elsif (ref($perl) and ("$perl" =~ /^([^=]+)=(\w+)/o)) {
223 JSON->register_class_hint(name => $name, hint => $name, type => lc($type));
224 $output .= perl2JSON(undef,$perl);
226 $perl =~ s{\\}{\\\\}sgo;
227 $perl =~ s/"/\\"/sgo;
228 $perl =~ s/\t/\\t/sgo;
229 $perl =~ s/\f/\\f/sgo;
230 $perl =~ s/\r/\\r/sgo;
231 $perl =~ s/\n/\\n/sgo;
232 $perl =~ s/(\pM)/sprintf('\u%0.4x',ord($1))/sgoe;
233 $output = '"'.$perl.'"';
240 sub perl2prettyJSON {
241 my ($class, $perl, $nospace) = @_;
245 if (!defined($perl)) {
246 $output = " "x$depth unless($nospace);
248 } elsif (ref($perl) and ref($perl) =~ /^JSON/) {
249 $output = " "x$depth unless($nospace);
251 } elsif ( ref($perl) && exists($_class_map{classes}{ref($perl)}) ) {
254 $output .= " "x$depth;
255 $output .= '/*--S '.$_class_map{classes}{ref($perl)}{hint}."--*/ ";
256 if (lc($_class_map{classes}{ref($perl)}{type}) eq 'hash') {
258 $output .= perl2prettyJSON(\%hash,undef,1);
259 } elsif (lc($_class_map{classes}{ref($perl)}{type}) eq 'array') {
261 $output .= perl2prettyJSON(\@array,undef,1);
263 $output .= ' /*--E '.$_class_map{classes}{ref($perl)}{hint}.'--*/';
265 } elsif (ref($perl) and ref($perl) =~ /HASH/) {
266 $output .= " "x$depth unless ($nospace);
270 for my $key (sort keys %$perl) {
271 $output .= ",\n" if ($c);
273 $output .= perl2prettyJSON($key)." : ".perl2prettyJSON($$perl{$key}, undef, 1);
278 $output .= " "x$depth;
280 } elsif (ref($perl) and ref($perl) =~ /ARRAY/) {
281 $output .= " "x$depth unless ($nospace);
285 for my $part (@$perl) {
286 $output .= ",\n" if ($c);
288 $output .= perl2prettyJSON($part);
293 $output .= " "x$depth;
295 } elsif (ref($perl) and "$perl" =~ /^([^=]+)=(\w{4,5})\(0x/) {
298 register_class_hint(undef, name => $name, hint => $name, type => lc($type));
299 $output .= perl2prettyJSON(undef,$perl);
301 $perl =~ s/\\/\\\\/sgo;
302 $perl =~ s/"/\\"/sgo;
303 $perl =~ s/\t/\\t/sgo;
304 $perl =~ s/\f/\\f/sgo;
305 $perl =~ s/\r/\\r/sgo;
306 $perl =~ s/\n/\\n/sgo;
307 $perl =~ s/(\pM)/sprintf('\u%0.4x',ord($1))/sgoe;
308 $output .= " "x$depth unless($nospace);
309 $output .= '"'.$perl.'"';