line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MarpaX::Demo::JSONParser; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
1184
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
39
|
|
4
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
28
|
|
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
6
|
use File::Basename; # For basename. |
|
1
|
|
|
|
|
33
|
|
|
1
|
|
|
|
|
126
|
|
7
|
1
|
|
|
1
|
|
1337
|
use File::Slurp; # For read_file(). |
|
1
|
|
|
|
|
17938
|
|
|
1
|
|
|
|
|
76
|
|
8
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
909
|
use Marpa::R2; |
|
1
|
|
|
|
|
194398
|
|
|
1
|
|
|
|
|
89
|
|
10
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
737
|
use MarpaX::Demo::JSONParser::Actions; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
34
|
|
12
|
1
|
|
|
1
|
|
976
|
use MarpaX::Simple qw(gen_parser); |
|
1
|
|
|
|
|
9166
|
|
|
1
|
|
|
|
|
79
|
|
13
|
|
|
|
|
|
|
|
14
|
1
|
|
|
1
|
|
1465
|
use Moo; |
|
1
|
|
|
|
|
27764
|
|
|
1
|
|
|
|
|
11
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
has base_name => |
17
|
|
|
|
|
|
|
( |
18
|
|
|
|
|
|
|
default => sub {return ''}, |
19
|
|
|
|
|
|
|
is => 'rw', |
20
|
|
|
|
|
|
|
# isa => 'Str', |
21
|
|
|
|
|
|
|
required => 0, |
22
|
|
|
|
|
|
|
); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
has bnf_file => |
25
|
|
|
|
|
|
|
( |
26
|
|
|
|
|
|
|
default => sub {return ''}, |
27
|
|
|
|
|
|
|
is => 'rw', |
28
|
|
|
|
|
|
|
# isa => 'Str', |
29
|
|
|
|
|
|
|
required => 1, |
30
|
|
|
|
|
|
|
); |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
has grammar => |
33
|
|
|
|
|
|
|
( |
34
|
|
|
|
|
|
|
default => sub {return ''}, |
35
|
|
|
|
|
|
|
is => 'rw', |
36
|
|
|
|
|
|
|
# isa => 'Marpa::R2::Scanless::G', |
37
|
|
|
|
|
|
|
required => 0, |
38
|
|
|
|
|
|
|
); |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
has parser => |
41
|
|
|
|
|
|
|
( |
42
|
|
|
|
|
|
|
default => sub {return ''}, |
43
|
|
|
|
|
|
|
is => 'rw', |
44
|
|
|
|
|
|
|
# isa => 'Marpa::R2::Scanless::G', |
45
|
|
|
|
|
|
|
required => 0, |
46
|
|
|
|
|
|
|
); |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
has scanner => |
49
|
|
|
|
|
|
|
( |
50
|
|
|
|
|
|
|
default => sub {return ''}, |
51
|
|
|
|
|
|
|
is => 'rw', |
52
|
|
|
|
|
|
|
# isa => 'Marpa::R2::Scanless::R', |
53
|
|
|
|
|
|
|
required => 0, |
54
|
|
|
|
|
|
|
); |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
our $VERSION = '1.06'; |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# ------------------------------------------------ |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub BUILD |
61
|
|
|
|
|
|
|
{ |
62
|
60
|
|
|
60
|
0
|
460
|
my($self) = @_; |
63
|
60
|
|
|
|
|
482
|
my $bnf = read_file($self -> bnf_file, binmode => ':utf8'); |
64
|
|
|
|
|
|
|
|
65
|
60
|
|
|
|
|
36399
|
$self -> base_name(basename($self -> bnf_file) ); |
66
|
|
|
|
|
|
|
|
67
|
60
|
100
|
|
|
|
461
|
if ($self -> base_name eq 'json.1.bnf') |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
68
|
|
|
|
|
|
|
{ |
69
|
20
|
|
|
|
|
276
|
$self-> grammar |
70
|
|
|
|
|
|
|
( |
71
|
|
|
|
|
|
|
Marpa::R2::Scanless::G -> new |
72
|
|
|
|
|
|
|
({ |
73
|
|
|
|
|
|
|
default_action => 'do_first_arg', |
74
|
|
|
|
|
|
|
source => \$bnf, |
75
|
|
|
|
|
|
|
}) |
76
|
|
|
|
|
|
|
) |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
elsif ($self -> base_name eq 'json.2.bnf') |
79
|
|
|
|
|
|
|
{ |
80
|
20
|
|
|
|
|
271
|
$self-> grammar |
81
|
|
|
|
|
|
|
( |
82
|
|
|
|
|
|
|
Marpa::R2::Scanless::G -> new |
83
|
|
|
|
|
|
|
({ |
84
|
|
|
|
|
|
|
bless_package => 'MarpaX::Demo::JSONParser::Actions', |
85
|
|
|
|
|
|
|
source => \$bnf, |
86
|
|
|
|
|
|
|
}) |
87
|
|
|
|
|
|
|
) |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
elsif ($self -> base_name eq 'json.3.bnf') |
90
|
|
|
|
|
|
|
{ |
91
|
20
|
|
|
|
|
108
|
$self-> parser |
92
|
|
|
|
|
|
|
( |
93
|
|
|
|
|
|
|
gen_parser |
94
|
|
|
|
|
|
|
( |
95
|
|
|
|
|
|
|
grammar => $bnf, |
96
|
|
|
|
|
|
|
) |
97
|
|
|
|
|
|
|
); |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
else |
100
|
|
|
|
|
|
|
{ |
101
|
0
|
|
|
|
|
0
|
die "Unknown BNF. Use either 'json.[123].bnf'\n"; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
60
|
100
|
|
|
|
5493542
|
if ($self -> base_name ne 'json.3.bnf') |
105
|
|
|
|
|
|
|
{ |
106
|
40
|
|
|
|
|
478
|
$self -> scanner |
107
|
|
|
|
|
|
|
( |
108
|
|
|
|
|
|
|
Marpa::R2::Scanless::R -> new |
109
|
|
|
|
|
|
|
({ |
110
|
|
|
|
|
|
|
grammar => $self -> grammar, |
111
|
|
|
|
|
|
|
semantics_package => 'MarpaX::Demo::JSONParser::Actions', |
112
|
|
|
|
|
|
|
}) |
113
|
|
|
|
|
|
|
); |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
} # End of BUILD. |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
# ------------------------------------------------ |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub decode_string |
121
|
|
|
|
|
|
|
{ |
122
|
2
|
|
|
2
|
0
|
8
|
my ($self, $s) = @_; |
123
|
|
|
|
|
|
|
|
124
|
2
|
|
|
|
|
16
|
$s =~ s/\\u([0-9A-Fa-f]{4})/chr(hex($1))/eg; |
|
1
|
|
|
|
|
9
|
|
125
|
2
|
|
|
|
|
7
|
$s =~ s/\\n/\n/g; |
126
|
2
|
|
|
|
|
6
|
$s =~ s/\\r/\r/g; |
127
|
2
|
|
|
|
|
6
|
$s =~ s/\\b/\b/g; |
128
|
2
|
|
|
|
|
7
|
$s =~ s/\\f/\f/g; |
129
|
2
|
|
|
|
|
8
|
$s =~ s/\\t/\t/g; |
130
|
2
|
|
|
|
|
6
|
$s =~ s/\\\\/\\/g; |
131
|
2
|
|
|
|
|
5
|
$s =~ s{\\/}{/}g; |
132
|
2
|
|
|
|
|
10
|
$s =~ s{\\"}{"}g; |
133
|
|
|
|
|
|
|
|
134
|
2
|
|
|
|
|
14
|
return $s; |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
} # End of decode_string. |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# ------------------------------------------------ |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub eval_json |
141
|
|
|
|
|
|
|
{ |
142
|
170
|
|
|
170
|
0
|
260
|
my($self, $thing) = @_; |
143
|
170
|
|
|
|
|
616
|
my($type) = ref $thing; |
144
|
|
|
|
|
|
|
|
145
|
170
|
100
|
|
|
|
919
|
if ($type eq 'REF') |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
146
|
|
|
|
|
|
|
{ |
147
|
14
|
|
|
|
|
25
|
return \$self -> eval_json( ${$thing} ); |
|
14
|
|
|
|
|
51
|
|
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
elsif ($type eq 'ARRAY') |
150
|
|
|
|
|
|
|
{ |
151
|
9
|
|
|
|
|
15
|
return [ map { $self -> eval_json($_) } @{$thing} ]; |
|
12
|
|
|
|
|
33
|
|
|
9
|
|
|
|
|
261
|
|
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
elsif ($type eq 'MarpaX::Demo::JSONParser::Actions::string') |
154
|
|
|
|
|
|
|
{ |
155
|
102
|
|
|
|
|
198
|
my($string) = substr $thing->[0], 1, -1; |
156
|
|
|
|
|
|
|
|
157
|
102
|
100
|
|
|
|
265
|
return $self -> decode_string($string) if ( index $string, '\\' ) >= 0; |
158
|
100
|
|
|
|
|
577
|
return $string; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
elsif ($type eq 'MarpaX::Demo::JSONParser::Actions::hash') |
161
|
|
|
|
|
|
|
{ |
162
|
20
|
|
|
|
|
41
|
return { map { $self -> eval_json( $_->[0] ), $self -> eval_json( $_->[1] ) } @{ $thing->[0] } }; |
|
65
|
|
|
|
|
366
|
|
|
20
|
|
|
|
|
54
|
|
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
25
|
100
|
|
|
|
231
|
return 1 if $type eq 'MarpaX::Demo::JSONParser::Actions::true'; |
166
|
24
|
100
|
|
|
|
81
|
return '' if $type eq 'MarpaX::Demo::JSONParser::Actions::false'; |
167
|
21
|
|
|
|
|
82
|
return $thing; |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
} # End of eval_json. |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# ------------------------------------------------ |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub parse |
174
|
|
|
|
|
|
|
{ |
175
|
60
|
|
|
60
|
1
|
15579
|
my($self, $string) = @_; |
176
|
|
|
|
|
|
|
|
177
|
60
|
100
|
|
|
|
289
|
if ($self -> base_name eq 'json.3.bnf') |
178
|
|
|
|
|
|
|
{ |
179
|
20
|
|
|
|
|
77
|
my $parse_value = $self -> parser -> ($string); |
180
|
|
|
|
|
|
|
|
181
|
14
|
|
|
|
|
137311
|
return $self -> post_process(@{$parse_value}); |
|
14
|
|
|
|
|
101
|
|
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
else |
184
|
|
|
|
|
|
|
{ |
185
|
40
|
|
|
|
|
291
|
$self -> scanner -> read(\$string); |
186
|
|
|
|
|
|
|
|
187
|
30
|
|
|
|
|
105775
|
my($value_ref) = $self -> scanner -> value; |
188
|
|
|
|
|
|
|
|
189
|
30
|
100
|
|
|
|
10830
|
die "Parse failed\n" if (! defined $value_ref); |
190
|
|
|
|
|
|
|
|
191
|
28
|
100
|
|
|
|
244
|
$value_ref = $self -> eval_json($value_ref) if ($self -> base_name eq 'json.2.bnf'); |
192
|
|
|
|
|
|
|
|
193
|
28
|
|
|
|
|
444
|
return $$value_ref; |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
} # End of parse. |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# ------------------------------------------------ |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub post_process |
201
|
|
|
|
|
|
|
{ |
202
|
264
|
|
|
264
|
0
|
487
|
my ($self, $type, @value) = @_; |
203
|
|
|
|
|
|
|
|
204
|
264
|
100
|
|
|
|
579
|
return $value[0] if $type eq 'number'; |
205
|
245
|
100
|
|
|
|
475
|
return undef if $type eq 'null'; |
206
|
243
|
100
|
|
|
|
898
|
return $value[0] if $type eq 'easy string'; |
207
|
140
|
100
|
|
|
|
256
|
return $self -> unescape($value[0]) if $type eq 'any char'; |
208
|
136
|
100
|
|
|
|
286
|
return chr(hex(substr($value[0],2))) if $type eq 'hex char'; |
209
|
135
|
100
|
|
|
|
235
|
return 1 if $type eq 'true'; |
210
|
134
|
100
|
|
|
|
275
|
return q{} if $type eq 'false'; |
211
|
|
|
|
|
|
|
|
212
|
131
|
100
|
|
|
|
304
|
if ($type eq 'array') |
213
|
|
|
|
|
|
|
{ |
214
|
9
|
|
|
|
|
13
|
my @result = (); |
215
|
9
|
|
|
|
|
13
|
push @result, $self -> post_process(@{$_}) for @{$value[0]}; |
|
9
|
|
|
|
|
19
|
|
|
12
|
|
|
|
|
34
|
|
216
|
|
|
|
|
|
|
|
217
|
9
|
|
|
|
|
47
|
return \@result; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
122
|
100
|
|
|
|
224
|
if ($type eq 'hash') |
221
|
|
|
|
|
|
|
{ |
222
|
20
|
|
|
|
|
51
|
my %result = (); |
223
|
|
|
|
|
|
|
|
224
|
20
|
|
|
|
|
41
|
for my $pair (@{$value[0]}) |
|
20
|
|
|
|
|
53
|
|
225
|
|
|
|
|
|
|
{ |
226
|
65
|
|
|
|
|
80
|
my $key = $self -> post_process(@{$pair->[0]}); |
|
65
|
|
|
|
|
198
|
|
227
|
65
|
|
|
|
|
88
|
$result{$key} = $self -> post_process(@{$pair->[1]}); |
|
65
|
|
|
|
|
155
|
|
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
20
|
|
|
|
|
116
|
return \%result; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
102
|
50
|
|
|
|
223
|
if ($type eq 'string') |
234
|
|
|
|
|
|
|
{ |
235
|
102
|
|
|
|
|
140
|
return join q{}, map { $self -> post_process( @{$_} ) } @{$value[0]}; |
|
108
|
|
|
|
|
113
|
|
|
108
|
|
|
|
|
265
|
|
|
102
|
|
|
|
|
194
|
|
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
0
|
|
|
|
|
0
|
die join q{ }, 'post process failed:', $type, @value; |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
} # End of post_process. |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# ------------------------------------------------ |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
sub unescape |
245
|
|
|
|
|
|
|
{ |
246
|
4
|
|
|
4
|
0
|
6
|
my($self, $char) = @_; |
247
|
|
|
|
|
|
|
|
248
|
4
|
50
|
|
|
|
13
|
return "\b" if $char eq 'b'; |
249
|
4
|
50
|
|
|
|
8
|
return "\f" if $char eq 'f'; |
250
|
4
|
50
|
|
|
|
9
|
return "\n" if $char eq 'n'; |
251
|
4
|
50
|
|
|
|
10
|
return "\r" if $char eq 'r'; |
252
|
4
|
50
|
|
|
|
8
|
return "\t" if $char eq 't'; |
253
|
4
|
50
|
|
|
|
9
|
return '/' if $char eq '/'; |
254
|
4
|
50
|
|
|
|
13
|
return '\\' if $char eq '\\'; |
255
|
4
|
50
|
|
|
|
16
|
return '"' if $char eq '"'; |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# If the character is not legal, return it anyway |
258
|
|
|
|
|
|
|
# As an alternative, we could fail here. |
259
|
|
|
|
|
|
|
|
260
|
0
|
|
|
|
|
|
return $char; |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
} # End of unescape. |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
# ------------------------------------------------ |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
1; |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=pod |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=head1 NAME |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
C - A JSON parser with a choice of grammars |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=head1 Synopsis |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
#!/usr/bin/env perl |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
use strict; |
279
|
|
|
|
|
|
|
use warnings; |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
use File::ShareDir; |
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) = File::ShareDir::dist_file($app_name, $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 share/json.1.bnf |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
This JSON grammar was devised by Peter Stuifzand. |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
=item o share/json.2.bnf |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
This JSON grammar was devised by Jeffrey Kegler. |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=item o share/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) under V 1.00. |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
From V 1.01 on, I use L and L to install them. |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
This a complex topic. Here are some of the issues: |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
=over 4 |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
=item o Module::Install makes it hard to update *META.* after you update the module's version # |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
It puts them in the dist but not in the current directory (alongside Makefile.PL, etc). |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=item o Install in the user's home directory, using L |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
Problem: Some CPAN testers run with accounts which don't have home directories. |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
I have used L when shipping modules, but that problem means I switched to L. But... |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
=item o Install in a shared directory, using L |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
Problem: Using L requires L during installation. |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
The latter has 77 bugs on RT, although some of them may have been fixed. |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
Problem: Using L requires using Makefile.PL rather that my preferred choice Build.PL. |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
Sigh. |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
Problem: Using L means the grammar files will be installed many directories deep. |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
Again, this is something I don't like doing. On my machine, there are 13 dir names listed when I run |
468
|
|
|
|
|
|
|
scripts/find.grammars.pl. |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
Problem: Using L by itself does not support author tests. |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
That needs L. |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
=back |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
Depite all this, for V 1.01 I've used L. And you can now run: |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
shell> perl scripts/find.grammars.pl |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
This reports the directory into which the grammars were installed. |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=head2 Which JSON BNF is best? |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
This is not really a fair question. They were developed under different circumstances. |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=over 4 |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
=item o json.1.bnf is by Peter Stuifzand. |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
json.1.bnf is the first attempt, when the Marpa SLIF still did not handle utf8. And it's meant to be a practical |
491
|
|
|
|
|
|
|
grammar. The sophisticated test suite is his, too. |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=item o json.2.bnf is by Jeffrey Kegler, the author of L. |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
json.2.bnf was written later, after Jeffey had a chance to study json.1.bnf. He used it to help optimise Marpa, |
496
|
|
|
|
|
|
|
but with a minimal test suite, so it had a different purpose. |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
I (Ron) converted their code into forms suitable for building this module. |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
=item o json.3.bnf is by Jeffrey Kegler. |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
He developed this in August, 2014, after recent significant progress in the writing of Marpa. |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
=head2 Where is Marpa's Homepage? |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
L. |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=head2 Are there any articles discussing Marpa? |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
Yes, many by its author, and several others. See Marpa's homepage, just above, and: |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
L, (in progress, by Peter Stuifzand and Ron Savage). |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
L, by Peter Stuifzand. |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
L, by Peter Stuifzand. |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
L, by Ron Savage. |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
=head1 See Also |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
L. |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
L. |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
L. |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
=head1 Machine-Readable Change Log |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
The file Changes was converted into Changelog.ini by L. |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
=head1 Version Numbers |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
Version numbers < 1.00 represent development versions. From 1.00 up, they are production versions. |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
=head1 Support |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
Email the author, or log a bug on RT: |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
L. |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
=head1 Author |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
L was written by Ron Savage Iron@savage.net.auE> in 2013. |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
Home page: L. |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
=head1 Copyright |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
Australian copyright (c) 2013, Ron Savage. |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
All Programs of mine are 'OSI Certified Open Source Software'; |
553
|
|
|
|
|
|
|
you can redistribute them and/or modify them under the terms of |
554
|
|
|
|
|
|
|
The Artistic License 2.0, a copy of which is available at: |
555
|
|
|
|
|
|
|
http://www.opensource.org/licenses/index.html |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
=cut |