File Coverage

blib/lib/Data/Pond.pm
Criterion Covered Total %
statement 109 110 99.0
branch 70 76 92.1
condition 3 3 100.0
subroutine 13 13 100.0
pod 2 2 100.0
total 197 204 96.5


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Data::Pond - Perl-based open notation for data
4              
5             =head1 SYNOPSIS
6              
7             use Data::Pond qw($pond_datum_rx);
8              
9             if($expr =~ /\A$pond_datum_rx\z/o) { ...
10             # and other regular expressions
11              
12             use Data::Pond qw(pond_read_datum pond_write_datum);
13              
14             $datum = pond_read_datum($text);
15             $text = pond_write_datum($datum);
16             $text = pond_write_datum($datum, { indent => 0 });
17              
18             =head1 DESCRIPTION
19              
20             This module is concerned with representing data structures in a textual
21             notation known as "Pond" (I

erl-based Ipen Iotation for Iata).

22             The notation is a strict subset of Perl expression syntax, but is intended
23             to have language-independent use. It is similar in spirit to JSON, which
24             is based on JavaScript, but Pond represents fewer data types directly.
25              
26             The data that can be represented in Pond consist of strings (of
27             characters), arrays, and string-keyed hashes. Arrays and hashes can
28             recursively (but not cyclically) contain any of these kinds of data.
29             This does not cover the full range of data types that Perl or other
30             languages can handle, but is intended to be a limited, fixed repertoire
31             of data types that many languages can readily process. It is intended
32             that more complex data can be represented using these basic types.
33             The arrays and hashes provide structuring facilities (ordered and
34             unordered collections, respectively), and strings are a convenient way
35             to represent atomic data.
36              
37             The Pond syntax is a subset of Perl expression syntax, consisting of
38             string literals and constructors for arrays and hashes. Strings may
39             be single-quoted or double-quoted, or may be decimal integer literals.
40             Double-quoted strings are restricted in which backslash sequences they
41             can use: the permitted ones are the single-character ones (such as C<\n>),
42             C<\x> sequences (such as C<\xe3> and C<\x{e3}>), and octal digit sequences
43             (such as C<\010>). Non-ASCII characters are acceptable in quoted strings.
44             Strings may also appear as pure-ASCII barewords, when they directly
45             precede C<< => >> in an array or hash constructor. Array (C<[]>) and hash
46             (C<{}>) constructors must contain data items separated by C<,> and C<<
47             => >> commas, and can have a trailing comma but not adjacent commas.
48             Whitespace is permitted where Perl allows it. Control characters are
49             not permitted, except for whitespace outside strings.
50              
51             A Pond expression can be Ced by Perl to yield the data item
52             that it represents, but this is not the recommended way to do it.
53             Any use of C on data opens up security issues. Instead use the
54             L function of this module, which does not use Perl's
55             parser but directly parses the restricted Pond syntax.
56              
57             This module is implemented in XS, with a pure Perl backup version for
58             systems that can't handle XS.
59              
60             =cut
61              
62             package Data::Pond;
63              
64 6     6   100150 { use 5.008; }
  6         22  
65 6     6   36 use warnings;
  6         14  
  6         218  
66 6     6   38 use strict;
  6         30  
  6         215  
67              
68             our $VERSION = "0.005";
69              
70 6     6   2461 use parent "Exporter";
  6         1519  
  6         37  
71             our @EXPORT_OK = qw(
72             $pond_string_rx $pond_ascii_string_rx
73             $pond_array_rx $pond_ascii_array_rx
74             $pond_hash_rx $pond_ascii_hash_rx
75             $pond_datum_rx $pond_ascii_datum_rx
76             pond_read_datum pond_write_datum
77             );
78              
79             =head1 REGULAR EXPRESSIONS
80              
81             Each of these regular expressions corresponds precisely to part of
82             Pond syntax. The regular expressions do not include any anchors, so to
83             check whether an entire string matches a production you must supply the
84             anchors yourself.
85              
86             The regular expressions with C<_ascii_> in the name match the subset
87             of the grammar that uses only ASCII characters. All Pond data can be
88             expressed using only ASCII characters.
89              
90             =over
91              
92             =item $pond_string_rx
93              
94             =item $pond_ascii_string_rx
95              
96             A string literal. This may be a double-quoted string, a single-quoted
97             string, or a decimal integer literal. It does not accept barewords.
98              
99             =cut
100              
101             my $pond_optwsp_rx = qr/[\t\n\f\r ]*/;
102              
103             my $pond_dqstringchar_rx = qr/[\ -\!\#\%-\?A-\[\]-\~\x{a1}-\x{7fffffff}]/;
104             my $pond_dqstring_rx = qr/(?>"(?:
105             $pond_dqstringchar_rx+
106             |\\(?:[\ -befnrt\{-\~\x{a1}-\x{7fffffff}]
107             |x(?:[0-9a-fA-F]|\{[0-9a-fA-F]+\}))
108             )*")/x;
109             my $pond_ascii_dqstring_rx = qr/(?>"(?:
110             [\ -\!\#\%-\?A-\[\]-\~]+
111             |\\(?:[\ -befnrt\{-\~]
112             |x(?:[0-9a-fA-F]|\{[0-9a-fA-F]+\}))
113             )*")/x;
114              
115             my $pond_sqstringchar_rx = qr/[\ -\&\(-\[\]-\~\x{a1}-\x{7fffffff}]/;
116             my $pond_sqstring_rx = qr/(?>'(?:
117             $pond_sqstringchar_rx+
118             |\\[\ -\~\x{a1}-\x{7fffffff}]
119             )*')/x;
120             my $pond_ascii_sqstring_rx = qr/(?>'(?:
121             [\ -\&\(-\[\]-\~]+
122             |\\[\ -\~]
123             )*')/x;
124              
125             my $pond_number_rx = qr/0|[1-9][0-9]*/;
126              
127             our $pond_string_rx = qr/$pond_dqstring_rx
128             |$pond_sqstring_rx
129             |$pond_number_rx/xo;
130             our $pond_ascii_string_rx = qr/$pond_ascii_dqstring_rx
131             |$pond_ascii_sqstring_rx
132             |$pond_number_rx/xo;
133              
134             my $pond_bareword_rx = qr/(?>[A-Za-z_][0-9A-Za-z_]*(?=$pond_optwsp_rx=>))/o;
135              
136             my $pond_interior_string_rx = qr/$pond_bareword_rx|$pond_string_rx/o;
137             my $pond_ascii_interior_string_rx =
138             qr/$pond_bareword_rx|$pond_ascii_string_rx/o;
139              
140             =item $pond_array_rx
141              
142             =item $pond_ascii_array_rx
143              
144             An array C<[]> constructor.
145              
146             =cut
147              
148 6     6   1924 my $pond_interior_datum_rx = do { use re "eval";
  6         13  
  6         512  
149             qr/$pond_bareword_rx|(??{$Data::Pond::pond_datum_rx})/o
150             };
151 6     6   40 my $pond_ascii_interior_datum_rx = do { use re "eval";
  6         14  
  6         2254  
152             qr/$pond_bareword_rx|(??{$Data::Pond::pond_ascii_datum_rx})/o
153             };
154              
155             my $pond_comma_rx = qr/,|=>/;
156              
157             our $pond_array_rx = qr/(?>\[$pond_optwsp_rx
158             (?>$pond_interior_datum_rx$pond_optwsp_rx
159             $pond_comma_rx$pond_optwsp_rx)*
160             (?:$pond_interior_datum_rx$pond_optwsp_rx)?
161             \])/xo;
162             our $pond_ascii_array_rx = qr/(?>\[$pond_optwsp_rx
163             (?>$pond_ascii_interior_datum_rx$pond_optwsp_rx
164             $pond_comma_rx$pond_optwsp_rx)*
165             (?:$pond_ascii_interior_datum_rx$pond_optwsp_rx)?
166             \])/xo;
167              
168             =item $pond_hash_rx
169              
170             =item $pond_ascii_hash_rx
171              
172             A hash C<{}> constructor.
173              
174             =cut
175              
176             my $pond_hashelem_rx = qr/
177             $pond_interior_string_rx$pond_optwsp_rx
178             $pond_comma_rx$pond_optwsp_rx$pond_interior_datum_rx
179             /xo;
180             my $pond_ascii_hashelem_rx = qr/
181             $pond_ascii_interior_string_rx$pond_optwsp_rx
182             $pond_comma_rx$pond_optwsp_rx$pond_ascii_interior_datum_rx
183             /xo;
184              
185             our $pond_hash_rx = qr/(?>\{$pond_optwsp_rx
186             (?>$pond_hashelem_rx$pond_optwsp_rx$pond_comma_rx$pond_optwsp_rx)*
187             (?:$pond_hashelem_rx$pond_optwsp_rx)?
188             \})/xo;
189             our $pond_ascii_hash_rx = qr/(?>\{$pond_optwsp_rx
190             (?>$pond_ascii_hashelem_rx$pond_optwsp_rx$pond_comma_rx$pond_optwsp_rx)*
191             (?:$pond_ascii_hashelem_rx$pond_optwsp_rx)?
192             \})/xo;
193              
194             =item $pond_datum_rx
195              
196             =item $pond_ascii_datum_rx
197              
198             Any permitted expression. This may be a string literal, array
199             constructor, or hash constructor.
200              
201             =cut
202              
203             our $pond_datum_rx = qr/$pond_string_rx
204             |$pond_array_rx
205             |$pond_hash_rx/xo;
206             our $pond_ascii_datum_rx = qr/$pond_ascii_string_rx
207             |$pond_ascii_array_rx
208             |$pond_ascii_hash_rx/xo;
209              
210             =back
211              
212             =cut
213              
214             eval { local $SIG{__DIE__};
215             require XSLoader;
216             XSLoader::load(__PACKAGE__, $VERSION);
217             };
218              
219             if($@ eq "") {
220             close(DATA);
221             } else {
222             (my $filename = __FILE__) =~ tr# -~##cd;
223             local $/ = undef;
224 3     3   1389 my $pp_code = "#line 223 \"$filename\"\n".;
  3         5581  
  3         4620  
225             close(DATA);
226             {
227             local $SIG{__DIE__};
228             eval $pp_code;
229             }
230             die $@ if $@ ne "";
231             }
232              
233             1;
234              
235             __DATA__