File Coverage

blib/lib/JSON/Decode/Regexp.pm
Criterion Covered Total %
statement 19 20 95.0
branch 8 10 80.0
condition n/a
subroutine 6 6 100.0
pod 1 1 100.0
total 34 37 91.8


line stmt bran cond sub pod time code
1             package JSON::Decode::Regexp;
2              
3             our $DATE = '2016-11-04'; # DATE
4             our $VERSION = '0.09'; # VERSION
5              
6 1     1   549 use 5.010001;
  1         3  
7 1     1   3 use strict;
  1         1  
  1         17  
8 1     1   3 use warnings;
  1         1  
  1         962  
9              
10             #use Data::Dumper;
11              
12             require Exporter;
13             our @ISA = qw(Exporter);
14             our @EXPORT_OK = qw(from_json);
15              
16 5     5   55 sub _fail { die __PACKAGE__.": $_[0] at offset ".pos()."\n" }
17              
18             my %escape_codes = (
19             "\\" => "\\",
20             "\"" => "\"",
21             "b" => "\b",
22             "f" => "\f",
23             "n" => "\n",
24             "r" => "\r",
25             "t" => "\t",
26             );
27              
28             sub _decode_str {
29 22     22   41 my $str = shift;
30 22         56 $str =~ s[(\\(?:([0-7]{1,3})|x([0-9A-Fa-f]{1,2})|(.)))]
31             [defined($2) ? chr(oct $2) :
32             defined($3) ? chr(hex $3) :
33 11 50       79 $escape_codes{$4} ? $escape_codes{$4} :
    100          
    100          
34             $1]eg;
35 22         95 $str;
36             }
37              
38             our $FROM_JSON = qr{
39              
40             (?:
41             (?&VALUE) (?{ $_ = $^R->[1] })
42             |
43             \z (?{ _fail "Unexpected end of input" })
44             |
45             (?{ _fail "Invalid literal" })
46             )
47              
48             (?(DEFINE)
49              
50             (?<OBJECT>
51             \{\s*
52             (?{ [$^R, {}] })
53             (?:
54             (?&KV) # [[$^R, {}], $k, $v]
55             (?{ [$^R->[0][0], {$^R->[1] => $^R->[2]}] })
56             \s*
57             (?:
58             (?:
59             ,\s* (?&KV) # [[$^R, {...}], $k, $v]
60             (?{ $^R->[0][1]{ $^R->[1] } = $^R->[2]; $^R->[0] })
61             )*
62             |
63             (?:[^,\}]|\z) (?{ _fail "Expected ',' or '\x7d'" })
64             )*
65             )?
66             \s*
67             (?:
68             \}
69             |
70             (?:.|\z) (?{ _fail "Expected closing of hash" })
71             )
72             )
73              
74             (?<KV>
75             (?&STRING) # [$^R, "string"]
76             \s*
77             (?:
78             :\s* (?&VALUE) # [[$^R, "string"], $value]
79             (?{ [$^R->[0][0], $^R->[0][1], $^R->[1]] })
80             |
81             (?:[^:]|\z) (?{ _fail "Expected ':'" })
82             )
83             )
84              
85             (?<ARRAY>
86             \[\s*
87             (?{ [$^R, []] })
88             (?:
89             (?&VALUE) # [[$^R, []], $val]
90             (?{ [$^R->[0][0], [$^R->[1]]] })
91             \s*
92             (?:
93             (?:
94             ,\s* (?&VALUE)
95             (?{ push @{$^R->[0][1]}, $^R->[1]; $^R->[0] })
96             )*
97             |
98             (?: [^,\]]|\z ) (?{ _fail "Expected ',' or '\x5d'" })
99             )
100             )?
101             \s*
102             (?:
103             \]
104             |
105             (?:.|\z) (?{ _fail "Expected closing of array" })
106             )
107             )
108              
109             (?<VALUE>
110             \s*
111             (
112             (?&STRING)
113             |
114             (?&NUMBER)
115             |
116             (?&OBJECT)
117             |
118             (?&ARRAY)
119             |
120             true (?{ [$^R, 1] })
121             |
122             false (?{ [$^R, 0] })
123             |
124             null (?{ [$^R, undef] })
125             )
126             \s*
127             )
128              
129             (?<STRING>
130             "
131             (
132             (?:
133             [^\\"]+
134             |
135             \\ [0-7]{1,3}
136             |
137             \\ x [0-9A-Fa-f]{1,2}
138             |
139             \\ ["\\/bfnrt]
140             #|
141             # \\ u [0-9a-fA-f]{4}
142             |
143             \\ (.) (?{ _fail "Invalid string escape character $^N" })
144             )*
145             )
146             (?:
147             "
148             |
149             (?:\\|\z) (?{ _fail "Expected closing of string" })
150             )
151              
152             (?{ [$^R, _decode_str($^N)] })
153             )
154              
155             (?<NUMBER>
156             (
157             -?
158             (?: 0 | [1-9]\d* )
159             (?: \. \d+ )?
160             (?: [eE] [-+]? \d+ )?
161             )
162              
163             (?{ [$^R, 0+$^N] })
164             )
165              
166             ) }xms;
167              
168             sub from_json {
169 21     21 1 2609 state $re = qr{\A$FROM_JSON\z};
170              
171 21         45 local $_ = shift;
172 21         24 local $^R;
173 21 100       23 eval { $_ =~ $re } and return $_;
  21         253  
174 5 50       39 die $@ if $@;
175 0           die 'no match';
176             }
177              
178             1;
179             # ABSTRACT: JSON parser as a single Perl Regex
180              
181             __END__
182              
183             =pod
184              
185             =encoding UTF-8
186              
187             =head1 NAME
188              
189             JSON::Decode::Regexp - JSON parser as a single Perl Regex
190              
191             =head1 VERSION
192              
193             This document describes version 0.09 of JSON::Decode::Regexp (from Perl distribution JSON-Decode-Regexp), released on 2016-11-04.
194              
195             =head1 SYNOPSIS
196              
197             use JSON::Decode::Regexp qw(from_json);
198             my $data = from_json(q([1, true, "a", {"b":null}]));
199              
200             =head1 DESCRIPTION
201              
202             This module is a packaging of Randal L. Schwartz' code (with some modification)
203             originally posted at:
204              
205             http://perlmonks.org/?node_id=995856
206              
207             The code is licensed "just like Perl".
208              
209             =head1 FUNCTIONS
210              
211             =head2 from_json($str) => DATA
212              
213             Decode JSON in C<$str>. Dies on error.
214              
215             =head1 FAQ
216              
217             =head2 How does this module compare to other JSON modules on CPAN?
218              
219             As of version 0.04, performance-wise this module quite on par with L<JSON::PP>
220             (faster on strings and longer arrays/objects, slower on simpler JSON) and a bit
221             slower than L<JSON::Tiny>. And of course all three are much slower than XS-based
222             modules like L<JSON::XS>.
223              
224             JSON::Decode::Regexp does not yet support Unicode, and does not pinpoint exact
225             location on parse error.
226              
227             In general, I don't see a point in using it in production (I recommend instead
228             L<JSON::XS> or L<Cpanel::JSON::XS> if you can use XS modules, or L<JSON::Tiny>
229             if you must use pure Perl modules). But it is a cool hack that demonstrates the
230             power of Perl regular expressions and beautiful code.
231              
232             =head1 HOMEPAGE
233              
234             Please visit the project's homepage at L<https://metacpan.org/release/JSON-Decode-Regexp>.
235              
236             =head1 SOURCE
237              
238             Source repository is at L<https://github.com/sharyanto/perl-JSON-Decode-Regexp>.
239              
240             =head1 BUGS
241              
242             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=JSON-Decode-Regexp>
243              
244             When submitting a bug or request, please include a test-file or a
245             patch to an existing test-file that illustrates the bug or desired
246             feature.
247              
248             =head1 SEE ALSO
249              
250             Pure-perl modules: L<JSON::Tiny>, L<JSON::PP>, L<Pegex::JSON>,
251             L<JSON::Decode::Marpa>.
252              
253             XS modules: L<JSON::XS>, L<Cpanel::JSON::XS>.
254              
255             =head1 AUTHOR
256              
257             perlancar <perlancar@cpan.org>
258              
259             =head1 COPYRIGHT AND LICENSE
260              
261             This software is copyright (c) 2016 by perlancar@cpan.org.
262              
263             This is free software; you can redistribute it and/or modify it under
264             the same terms as the Perl 5 programming language system itself.
265              
266             =cut