line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MarpaX::Demo::JSONParser; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
991
|
use strict; |
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
57
|
|
4
|
2
|
|
|
2
|
|
9
|
use warnings; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
66
|
|
5
|
|
|
|
|
|
|
|
6
|
2
|
|
|
2
|
|
12
|
use File::Basename; # For basename. |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
274
|
|
7
|
2
|
|
|
2
|
|
1002
|
use File::Slurper 'read_text'; |
|
2
|
|
|
|
|
27081
|
|
|
2
|
|
|
|
|
118
|
|
8
|
|
|
|
|
|
|
|
9
|
2
|
|
|
2
|
|
890
|
use Marpa::R2; |
|
2
|
|
|
|
|
295549
|
|
|
2
|
|
|
|
|
104
|
|
10
|
|
|
|
|
|
|
|
11
|
2
|
|
|
2
|
|
995
|
use MarpaX::Demo::JSONParser::Actions; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
72
|
|
12
|
2
|
|
|
2
|
|
1003
|
use MarpaX::Simple qw(gen_parser); |
|
2
|
|
|
|
|
6681
|
|
|
2
|
|
|
|
|
140
|
|
13
|
|
|
|
|
|
|
|
14
|
2
|
|
|
2
|
|
1014
|
use Moo; |
|
2
|
|
|
|
|
25187
|
|
|
2
|
|
|
|
|
11
|
|
15
|
|
|
|
|
|
|
|
16
|
2
|
|
|
2
|
|
4169
|
use Types::Standard qw/Any Str/; |
|
2
|
|
|
|
|
149209
|
|
|
2
|
|
|
|
|
23
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
has base_name => |
19
|
|
|
|
|
|
|
( |
20
|
|
|
|
|
|
|
default => sub {return ''}, |
21
|
|
|
|
|
|
|
is => 'rw', |
22
|
|
|
|
|
|
|
isa => Str, |
23
|
|
|
|
|
|
|
required => 0, |
24
|
|
|
|
|
|
|
); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
has bnf_file => |
27
|
|
|
|
|
|
|
( |
28
|
|
|
|
|
|
|
default => sub {return ''}, |
29
|
|
|
|
|
|
|
is => 'rw', |
30
|
|
|
|
|
|
|
isa => Str, |
31
|
|
|
|
|
|
|
required => 1, |
32
|
|
|
|
|
|
|
); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
has grammar => |
35
|
|
|
|
|
|
|
( |
36
|
|
|
|
|
|
|
default => sub {return ''}, |
37
|
|
|
|
|
|
|
is => 'rw', |
38
|
|
|
|
|
|
|
isa => Any, |
39
|
|
|
|
|
|
|
required => 0, |
40
|
|
|
|
|
|
|
); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
has parser => |
43
|
|
|
|
|
|
|
( |
44
|
|
|
|
|
|
|
default => sub {return ''}, |
45
|
|
|
|
|
|
|
is => 'rw', |
46
|
|
|
|
|
|
|
isa => Any, |
47
|
|
|
|
|
|
|
required => 0, |
48
|
|
|
|
|
|
|
); |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
has scanner => |
51
|
|
|
|
|
|
|
( |
52
|
|
|
|
|
|
|
default => sub {return ''}, |
53
|
|
|
|
|
|
|
is => 'rw', |
54
|
|
|
|
|
|
|
isa => Any, |
55
|
|
|
|
|
|
|
required => 0, |
56
|
|
|
|
|
|
|
); |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
our $VERSION = '1.08'; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# ------------------------------------------------ |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub BUILD |
63
|
|
|
|
|
|
|
{ |
64
|
60
|
|
|
60
|
0
|
1579
|
my($self) = @_; |
65
|
60
|
|
|
|
|
1160
|
my $bnf = read_text $self -> bnf_file; |
66
|
|
|
|
|
|
|
|
67
|
60
|
|
|
|
|
12801
|
$self -> base_name(basename($self -> bnf_file) ); |
68
|
|
|
|
|
|
|
|
69
|
60
|
100
|
|
|
|
7204
|
if ($self -> base_name eq 'json.1.bnf') |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
70
|
|
|
|
|
|
|
{ |
71
|
20
|
|
|
|
|
405
|
$self-> grammar |
72
|
|
|
|
|
|
|
( |
73
|
|
|
|
|
|
|
Marpa::R2::Scanless::G -> new |
74
|
|
|
|
|
|
|
({ |
75
|
|
|
|
|
|
|
default_action => 'do_first_arg', |
76
|
|
|
|
|
|
|
source => \$bnf, |
77
|
|
|
|
|
|
|
}) |
78
|
|
|
|
|
|
|
) |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
elsif ($self -> base_name eq 'json.2.bnf') |
81
|
|
|
|
|
|
|
{ |
82
|
20
|
|
|
|
|
791
|
$self-> grammar |
83
|
|
|
|
|
|
|
( |
84
|
|
|
|
|
|
|
Marpa::R2::Scanless::G -> new |
85
|
|
|
|
|
|
|
({ |
86
|
|
|
|
|
|
|
bless_package => 'MarpaX::Demo::JSONParser::Actions', |
87
|
|
|
|
|
|
|
source => \$bnf, |
88
|
|
|
|
|
|
|
}) |
89
|
|
|
|
|
|
|
) |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
elsif ($self -> base_name eq 'json.3.bnf') |
92
|
|
|
|
|
|
|
{ |
93
|
20
|
|
|
|
|
819
|
$self-> parser |
94
|
|
|
|
|
|
|
( |
95
|
|
|
|
|
|
|
gen_parser |
96
|
|
|
|
|
|
|
( |
97
|
|
|
|
|
|
|
grammar => $bnf, |
98
|
|
|
|
|
|
|
) |
99
|
|
|
|
|
|
|
); |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
else |
102
|
|
|
|
|
|
|
{ |
103
|
0
|
|
|
|
|
0
|
die "Unknown BNF. Use either 'json.[123].bnf'\n"; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
60
|
100
|
|
|
|
5653448
|
if ($self -> base_name ne 'json.3.bnf') |
107
|
|
|
|
|
|
|
{ |
108
|
40
|
|
|
|
|
1242
|
$self -> scanner |
109
|
|
|
|
|
|
|
( |
110
|
|
|
|
|
|
|
Marpa::R2::Scanless::R -> new |
111
|
|
|
|
|
|
|
({ |
112
|
|
|
|
|
|
|
grammar => $self -> grammar, |
113
|
|
|
|
|
|
|
semantics_package => 'MarpaX::Demo::JSONParser::Actions', |
114
|
|
|
|
|
|
|
}) |
115
|
|
|
|
|
|
|
); |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
} # End of BUILD. |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# ------------------------------------------------ |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub decode_string |
123
|
|
|
|
|
|
|
{ |
124
|
2
|
|
|
2
|
0
|
9
|
my ($self, $s) = @_; |
125
|
|
|
|
|
|
|
|
126
|
2
|
|
|
|
|
14
|
$s =~ s/\\u([0-9A-Fa-f]{4})/chr(hex($1))/eg; |
|
1
|
|
|
|
|
10
|
|
127
|
2
|
|
|
|
|
10
|
$s =~ s/\\n/\n/g; |
128
|
2
|
|
|
|
|
7
|
$s =~ s/\\r/\r/g; |
129
|
2
|
|
|
|
|
6
|
$s =~ s/\\b/\b/g; |
130
|
2
|
|
|
|
|
7
|
$s =~ s/\\f/\f/g; |
131
|
2
|
|
|
|
|
7
|
$s =~ s/\\t/\t/g; |
132
|
2
|
|
|
|
|
7
|
$s =~ s/\\\\/\\/g; |
133
|
2
|
|
|
|
|
7
|
$s =~ s{\\/}{/}g; |
134
|
2
|
|
|
|
|
10
|
$s =~ s{\\"}{"}g; |
135
|
|
|
|
|
|
|
|
136
|
2
|
|
|
|
|
16
|
return $s; |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
} # End of decode_string. |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# ------------------------------------------------ |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub eval_json |
143
|
|
|
|
|
|
|
{ |
144
|
170
|
|
|
170
|
0
|
475
|
my($self, $thing) = @_; |
145
|
170
|
|
|
|
|
297
|
my($type) = ref $thing; |
146
|
|
|
|
|
|
|
|
147
|
170
|
100
|
|
|
|
494
|
if ($type eq 'REF') |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
148
|
|
|
|
|
|
|
{ |
149
|
14
|
|
|
|
|
40
|
return \$self -> eval_json( ${$thing} ); |
|
14
|
|
|
|
|
58
|
|
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
elsif ($type eq 'ARRAY') |
152
|
|
|
|
|
|
|
{ |
153
|
9
|
|
|
|
|
16
|
return [ map { $self -> eval_json($_) } @{$thing} ]; |
|
12
|
|
|
|
|
32
|
|
|
9
|
|
|
|
|
28
|
|
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
elsif ($type eq 'MarpaX::Demo::JSONParser::Actions::string') |
156
|
|
|
|
|
|
|
{ |
157
|
102
|
|
|
|
|
226
|
my($string) = substr $thing->[0], 1, -1; |
158
|
|
|
|
|
|
|
|
159
|
102
|
100
|
|
|
|
244
|
return $self -> decode_string($string) if ( index $string, '\\' ) >= 0; |
160
|
100
|
|
|
|
|
312
|
return $string; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
elsif ($type eq 'MarpaX::Demo::JSONParser::Actions::hash') |
163
|
|
|
|
|
|
|
{ |
164
|
20
|
|
|
|
|
71
|
return { map { $self -> eval_json( $_->[0] ), $self -> eval_json( $_->[1] ) } @{ $thing->[0] } }; |
|
65
|
|
|
|
|
149
|
|
|
20
|
|
|
|
|
58
|
|
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
25
|
100
|
|
|
|
98
|
return 1 if $type eq 'MarpaX::Demo::JSONParser::Actions::true'; |
168
|
24
|
100
|
|
|
|
109
|
return '' if $type eq 'MarpaX::Demo::JSONParser::Actions::false'; |
169
|
21
|
|
|
|
|
79
|
return $thing; |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
} # End of eval_json. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# ------------------------------------------------ |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub parse |
176
|
|
|
|
|
|
|
{ |
177
|
60
|
|
|
60
|
1
|
19313
|
my($self, $string) = @_; |
178
|
|
|
|
|
|
|
|
179
|
60
|
100
|
|
|
|
1109
|
if ($self -> base_name eq 'json.3.bnf') |
180
|
|
|
|
|
|
|
{ |
181
|
20
|
|
|
|
|
414
|
my $parse_value = $self -> parser -> ($string); |
182
|
|
|
|
|
|
|
|
183
|
14
|
|
|
|
|
143325
|
return $self -> post_process(@{$parse_value}); |
|
14
|
|
|
|
|
82
|
|
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
else |
186
|
|
|
|
|
|
|
{ |
187
|
40
|
|
|
|
|
888
|
$self -> scanner -> read(\$string); |
188
|
|
|
|
|
|
|
|
189
|
30
|
|
|
|
|
116472
|
my($value_ref) = $self -> scanner -> value; |
190
|
|
|
|
|
|
|
|
191
|
30
|
100
|
|
|
|
12835
|
die "Parse failed\n" if (! defined $value_ref); |
192
|
|
|
|
|
|
|
|
193
|
28
|
100
|
|
|
|
846
|
$value_ref = $self -> eval_json($value_ref) if ($self -> base_name eq 'json.2.bnf'); |
194
|
|
|
|
|
|
|
|
195
|
28
|
|
|
|
|
281
|
return $$value_ref; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
} # End of parse. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# ------------------------------------------------ |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
sub post_process |
203
|
|
|
|
|
|
|
{ |
204
|
264
|
|
|
264
|
0
|
431
|
my ($self, $type, @value) = @_; |
205
|
|
|
|
|
|
|
|
206
|
264
|
100
|
|
|
|
458
|
return $value[0] if $type eq 'number'; |
207
|
245
|
100
|
|
|
|
379
|
return undef if $type eq 'null'; |
208
|
243
|
100
|
|
|
|
581
|
return $value[0] if $type eq 'easy string'; |
209
|
140
|
100
|
|
|
|
210
|
return $self -> unescape($value[0]) if $type eq 'any char'; |
210
|
136
|
100
|
|
|
|
250
|
return chr(hex(substr($value[0],2))) if $type eq 'hex char'; |
211
|
135
|
100
|
|
|
|
214
|
return 1 if $type eq 'true'; |
212
|
134
|
100
|
|
|
|
210
|
return q{} if $type eq 'false'; |
213
|
|
|
|
|
|
|
|
214
|
131
|
100
|
|
|
|
191
|
if ($type eq 'array') |
215
|
|
|
|
|
|
|
{ |
216
|
9
|
|
|
|
|
14
|
my @result = (); |
217
|
9
|
|
|
|
|
15
|
push @result, $self -> post_process(@{$_}) for @{$value[0]}; |
|
9
|
|
|
|
|
24
|
|
|
12
|
|
|
|
|
21
|
|
218
|
|
|
|
|
|
|
|
219
|
9
|
|
|
|
|
45
|
return \@result; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
122
|
100
|
|
|
|
193
|
if ($type eq 'hash') |
223
|
|
|
|
|
|
|
{ |
224
|
20
|
|
|
|
|
35
|
my %result = (); |
225
|
|
|
|
|
|
|
|
226
|
20
|
|
|
|
|
32
|
for my $pair (@{$value[0]}) |
|
20
|
|
|
|
|
36
|
|
227
|
|
|
|
|
|
|
{ |
228
|
65
|
|
|
|
|
91
|
my $key = $self -> post_process(@{$pair->[0]}); |
|
65
|
|
|
|
|
132
|
|
229
|
65
|
|
|
|
|
96
|
$result{$key} = $self -> post_process(@{$pair->[1]}); |
|
65
|
|
|
|
|
104
|
|
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
20
|
|
|
|
|
137
|
return \%result; |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
102
|
50
|
|
|
|
156
|
if ($type eq 'string') |
236
|
|
|
|
|
|
|
{ |
237
|
102
|
|
|
|
|
122
|
return join q{}, map { $self -> post_process( @{$_} ) } @{$value[0]}; |
|
108
|
|
|
|
|
141
|
|
|
108
|
|
|
|
|
188
|
|
|
102
|
|
|
|
|
142
|
|
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
0
|
|
|
|
|
0
|
die join q{ }, 'post process failed:', $type, @value; |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
} # End of post_process. |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
# ------------------------------------------------ |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub unescape |
247
|
|
|
|
|
|
|
{ |
248
|
4
|
|
|
4
|
0
|
9
|
my($self, $char) = @_; |
249
|
|
|
|
|
|
|
|
250
|
4
|
50
|
|
|
|
7
|
return "\b" if $char eq 'b'; |
251
|
4
|
50
|
|
|
|
10
|
return "\f" if $char eq 'f'; |
252
|
4
|
50
|
|
|
|
9
|
return "\n" if $char eq 'n'; |
253
|
4
|
50
|
|
|
|
7
|
return "\r" if $char eq 'r'; |
254
|
4
|
50
|
|
|
|
9
|
return "\t" if $char eq 't'; |
255
|
4
|
50
|
|
|
|
9
|
return '/' if $char eq '/'; |
256
|
4
|
50
|
|
|
|
8
|
return '\\' if $char eq '\\'; |
257
|
4
|
50
|
|
|
|
11
|
return '"' if $char eq '"'; |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
# If the character is not legal, return it anyway |
260
|
|
|
|
|
|
|
# As an alternative, we could fail here. |
261
|
|
|
|
|
|
|
|
262
|
0
|
|
|
|
|
|
return $char; |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
} # End of unescape. |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# ------------------------------------------------ |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
1; |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=pod |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=head1 NAME |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
C - A JSON parser with a choice of grammars |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=head1 Synopsis |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
#!/usr/bin/env perl |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
use strict; |
281
|
|
|
|
|
|
|
use warnings; |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
use MarpaX::Demo::JSONParser; |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
use Try::Tiny; |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
my($app_name) = 'MarpaX-Demo-JSONParser'; |
288
|
|
|
|
|
|
|
my($bnf_name) = 'json.1.bnf'; # Or 'json.2.bnf'. See scripts/find.grammars.pl below. |
289
|
|
|
|
|
|
|
my($bnf_file) = "data/$bnf_name"; |
290
|
|
|
|
|
|
|
my($string) = '{"test":"1.25e4"}'; |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
my($message); |
293
|
|
|
|
|
|
|
my($result); |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
# Use try to catch die. |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
try |
298
|
|
|
|
|
|
|
{ |
299
|
|
|
|
|
|
|
$message = ''; |
300
|
|
|
|
|
|
|
$result = MarpaX::Demo::JSONParser -> new(bnf_file => $bnf_file) -> parse($string); |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
catch |
303
|
|
|
|
|
|
|
{ |
304
|
|
|
|
|
|
|
$message = $_; |
305
|
|
|
|
|
|
|
$result = 0; |
306
|
|
|
|
|
|
|
}; |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
print $result ? "Result: test => $$result{test}. Expect: 1.25e4. \n" : "Parse failed. $message"; |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
This script ships as scripts/demo.pl. |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
You can test failure by deleting the '{' character in line 17 of demo.pl and re-running it. |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
See also t/basic.tests.t for more sample code. |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head1 Description |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
C demonstrates 2 grammars for parsing JSON. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
Only 1 grammar is loaded per run, as specified by the C option to C<< new() >>. |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
See t/basic.tests.t for sample code. |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=head1 Installation |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
Install C as you would for any C module: |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
Run: |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
cpanm MarpaX::Demo::JSONParser |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
or run: |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
sudo cpan MarpaX::Demo::JSONParser |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
or unpack the distro, and then either: |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
perl Build.PL |
339
|
|
|
|
|
|
|
./Build |
340
|
|
|
|
|
|
|
./Build test |
341
|
|
|
|
|
|
|
sudo ./Build install |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
or: |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
perl Makefile.PL |
346
|
|
|
|
|
|
|
make (or dmake or nmake) |
347
|
|
|
|
|
|
|
make test |
348
|
|
|
|
|
|
|
make install |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=head1 Constructor and Initialization |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
C is called as C<< my($parser) = MarpaX::Demo::JSONParser -> new(k1 => v1, k2 => v2, ...) >>. |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
It returns a new object of type C. |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
Key-value pairs accepted in the parameter list (see corresponding methods for details |
357
|
|
|
|
|
|
|
[e.g. bnf_file([$string])]): |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=over 4 |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
=item o bnf_file aUserGrammarFileName |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
Specify the name of the file containing your Marpa::R2-style grammar. |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
See data/json.1.bnf, data/json.2.bnf and data/json.3.bnf for the cases handled by the code. |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
This option is mandatory. |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
Default: ''. |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=back |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=head1 Methods |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=head2 parse($string) |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
Parses the given $string using the grammar whose file name was provided by the C option to |
378
|
|
|
|
|
|
|
C<< new() >>. |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
Dies if the parse fails, or returns the result of the parse if it succeeded. |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
=head1 Files Shipped with this Module |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=head2 Data Files |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
These JSON grammars are discussed in the L below. |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
=over 4 |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
=item o data/json.1.bnf |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
This JSON grammar was devised by Peter Stuifzand. |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
=item o data/json.2.bnf |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
This JSON grammar was devised by Jeffrey Kegler. |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=item o data/json.3.bnf |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
This JSON grammar was devised by Jeffrey Kegler. |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
=back |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=head2 Scripts |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
=over 4 |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
=item o scripts/demo.pl |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
This program is exactly what is displayed in the L above. |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
Before installation of this module, run it with: |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
shell> perl -Ilib scripts/demo.pl |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
And after installation, just use: |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
shell> perl scripts/demo.pl |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
=item o scripts/find.grammars.pl |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
After installation of the module, run it with: |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
shell> perl scripts/find.grammars.pl (Defaults to json.1.bnf) |
425
|
|
|
|
|
|
|
shell> perl scripts/find.grammars.pl json.1.bnf |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
Or use json.2.bnf or json.2.bnf. |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
It will print the name of the path to given grammar file. |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=back |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
=head1 FAQ |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=head2 Where are the grammar files actually installed? |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
They are not installed (when the source code is). They are shipped in the data/ dir. |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
I used to use L and L to install them, but Module::Install is now |
440
|
|
|
|
|
|
|
unusable. See Changes for details. |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=head2 Which JSON BNF is best? |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
This is not really a fair question. They were developed under different circumstances. |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
=over 4 |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
=item o json.1.bnf is by Peter Stuifzand. |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
json.1.bnf is the first attempt, when the Marpa SLIF still did not handle utf8. And it's meant to be a practical |
451
|
|
|
|
|
|
|
grammar. The sophisticated test suite is his, too. |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=item o json.2.bnf is by Jeffrey Kegler, the author of L. |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
json.2.bnf was written later, after Jeffey had a chance to study json.1.bnf. He used it to help optimise Marpa, |
456
|
|
|
|
|
|
|
but with a minimal test suite, so it had a different purpose. |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
I (Ron) converted their code into forms suitable for building this module. |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=item o json.3.bnf is by Jeffrey Kegler. |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
He developed this in August, 2014, after recent significant progress in the writing of Marpa. |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
=back |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=head2 Where is Marpa's Homepage? |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
L. |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
=head2 Are there any articles discussing Marpa? |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
Yes, many by its author, and several others. See Marpa's homepage, just above, and: |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
L, (in progress, by Peter Stuifzand and Ron Savage). |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
L, by Peter Stuifzand. |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
L, by Peter Stuifzand. |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
L, by Ron Savage. |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=head1 See Also |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
L. |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
L. |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
L. |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=head1 Machine-Readable Change Log |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
The file Changes was converted into Changelog.ini by L. |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
=head1 Repository |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
L |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
=head1 Version Numbers |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
Version numbers < 1.00 represent development versions. From 1.00 up, they are production versions. |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
=head1 Support |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
Email the author, or log a bug on RT: |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
L. |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=head1 Author |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
L was written by Ron Savage Iron@savage.net.auE> in 2013. |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
Home page: L. |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=head1 Copyright |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
Australian copyright (c) 2013, Ron Savage. |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
All Programs of mine are 'OSI Certified Open Source Software'; |
519
|
|
|
|
|
|
|
you can redistribute them and/or modify them under the terms of |
520
|
|
|
|
|
|
|
The Perl License, a copy of which is available at: |
521
|
|
|
|
|
|
|
http://www.opensource.org/licenses/index.html |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=cut |