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 $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
4             our $DATE = '2021-08-01'; # DATE
5             our $DIST = 'JSON-Decode-Regexp'; # DIST
6             our $VERSION = '0.102'; # VERSION
7              
8 1     1   615 use 5.014004;
  1         9  
9 1     1   7 use strict;
  1         2  
  1         20  
10 1     1   5 use warnings;
  1         47  
  1         1144  
11              
12             #use Data::Dumper;
13              
14             require Exporter;
15             our @ISA = qw(Exporter);
16             our @EXPORT_OK = qw(from_json);
17              
18 5     5   41 sub _fail { die __PACKAGE__.": $_[0] at offset ".pos()."\n" }
19              
20             my %escape_codes = (
21             "\\" => "\\",
22             "\"" => "\"",
23             "b" => "\b",
24             "f" => "\f",
25             "n" => "\n",
26             "r" => "\r",
27             "t" => "\t",
28             );
29              
30             sub _decode_str {
31 22     22   61 my $str = shift;
32 22         66 $str =~ s[(\\(?:([0-7]{1,3})|x([0-9A-Fa-f]{1,2})|(.)))]
33             [defined($2) ? chr(oct $2) :
34 11 50       71 defined($3) ? chr(hex $3) :
    100          
    100          
35             $escape_codes{$4} ? $escape_codes{$4} :
36 22         126 $1]eg;
37             $str;
38             }
39              
40             our $FROM_JSON = qr{
41              
42             (?:
43             (?&VALUE) (?{ $_ = $^R->[1] })
44             |
45             \z (?{ _fail "Unexpected end of input" })
46             |
47             (?{ _fail "Invalid literal" })
48             )
49              
50             (?(DEFINE)
51              
52             (?
53             \{\s*
54             (?{ [$^R, {}] })
55             (?:
56             (?&KV) # [[$^R, {}], $k, $v]
57             (?{ [$^R->[0][0], {$^R->[1] => $^R->[2]}] })
58             \s*
59             (?:
60             (?:
61             ,\s* (?&KV) # [[$^R, {...}], $k, $v]
62             (?{ $^R->[0][1]{ $^R->[1] } = $^R->[2]; $^R->[0] })
63             )*
64             |
65             (?:[^,\}]|\z) (?{ _fail "Expected ',' or '\x7d'" })
66             )*
67             )?
68             \s*
69             (?:
70             \}
71             |
72             (?:.|\z) (?{ _fail "Expected closing of hash" })
73             )
74             )
75              
76             (?
77             (?&STRING) # [$^R, "string"]
78             \s*
79             (?:
80             :\s* (?&VALUE) # [[$^R, "string"], $value]
81             (?{ [$^R->[0][0], $^R->[0][1], $^R->[1]] })
82             |
83             (?:[^:]|\z) (?{ _fail "Expected ':'" })
84             )
85             )
86              
87             (?
88             \[\s*
89             (?{ [$^R, []] })
90             (?:
91             (?&VALUE) # [[$^R, []], $val]
92             (?{ [$^R->[0][0], [$^R->[1]]] })
93             \s*
94             (?:
95             (?:
96             ,\s* (?&VALUE)
97             (?{ push @{$^R->[0][1]}, $^R->[1]; $^R->[0] })
98             )*
99             |
100             (?: [^,\]]|\z ) (?{ _fail "Expected ',' or '\x5d'" })
101             )
102             )?
103             \s*
104             (?:
105             \]
106             |
107             (?:.|\z) (?{ _fail "Expected closing of array" })
108             )
109             )
110              
111             (?
112             \s*
113             (
114             (?&STRING)
115             |
116             (?&NUMBER)
117             |
118             (?&OBJECT)
119             |
120             (?&ARRAY)
121             |
122             true (?{ [$^R, 1] })
123             |
124             false (?{ [$^R, 0] })
125             |
126             null (?{ [$^R, undef] })
127             )
128             \s*
129             )
130              
131             (?
132             "
133             (
134             (?:
135             [^\\"]+
136             |
137             \\ [0-7]{1,3}
138             |
139             \\ x [0-9A-Fa-f]{1,2}
140             |
141             \\ ["\\/bfnrt]
142             #|
143             # \\ u [0-9a-fA-f]{4}
144             |
145             \\ (.) (?{ _fail "Invalid string escape character $^N" })
146             )*
147             )
148             (?:
149             "
150             |
151             (?:\\|\z) (?{ _fail "Expected closing of string" })
152             )
153              
154             (?{ [$^R, _decode_str($^N)] })
155             )
156              
157             (?
158             (
159             -?
160             (?: 0 | [1-9][0-9]* )
161             (?: \. [0-9]+ )?
162             (?: [eE] [-+]? [0-9]+ )?
163             )
164              
165             (?{ [$^R, 0+$^N] })
166             )
167              
168             ) }xms;
169              
170 21     21 1 1785 sub from_json {
171             state $re = qr{\A$FROM_JSON\z};
172 21         49  
173 21         33 local $_ = shift;
174 21 100       31 local $^R;
  21         226  
175 5 50       31 eval { $_ =~ $re } and return $_;
176 0           die $@ if $@;
177             die 'no match';
178             }
179              
180             1;
181             # ABSTRACT: JSON parser as a single Perl Regex
182              
183             __END__