File Coverage

blib/lib/Astro/VEX/Parse.pm
Criterion Covered Total %
statement 51 51 100.0
branch 2 4 50.0
condition n/a
subroutine 15 15 100.0
pod 0 1 0.0
total 68 71 95.7


line stmt bran cond sub pod time code
1             package Astro::VEX::Parse;
2              
3             =head1 NAME
4              
5             Astro::VEX::Parse - VEX (VLBI Experiment Definition) parser module
6              
7             =cut
8              
9 2     2   1949 use strict;
  2         3  
  2         50  
10 2     2   8 use warnings;
  2         3  
  2         68  
11              
12             our $VERSION = '0.001';
13              
14 2     2   2018 use Parse::RecDescent;
  2         71393  
  2         18  
15              
16 2     2   92 use Astro::VEX;
  2         5  
  2         40  
17 2     2   949 use Astro::VEX::Block;
  2         5  
  2         54  
18 2     2   707 use Astro::VEX::Comment;
  2         5  
  2         48  
19 2     2   676 use Astro::VEX::Def;
  2         4  
  2         48  
20 2     2   723 use Astro::VEX::Link;
  2         5  
  2         47  
21 2     2   668 use Astro::VEX::Param;
  2         5  
  2         45  
22 2     2   727 use Astro::VEX::Param::Empty;
  2         6  
  2         48  
23 2     2   717 use Astro::VEX::Param::Number;
  2         5  
  2         45  
24 2     2   701 use Astro::VEX::Param::String;
  2         5  
  2         48  
25 2     2   710 use Astro::VEX::Ref;
  2         5  
  2         51  
26 2     2   684 use Astro::VEX::Scan;
  2         4  
  2         340  
27              
28             my $grammar = q{
29             vex: header content(s?)
30             {new Astro::VEX(version => $item[1], content => $item[2]);}
31              
32             header: 'VEX_rev' '=' /\d+\.\d+/ ';'
33             {$item[3];}
34              
35             content: comment | block
36              
37             comment: '*' /.*/
38             {new Astro::VEX::Comment($item[3]);}
39              
40             block: block_header block_content(s?)
41             {new Astro::VEX::Block($item[1], $item[2]);}
42              
43             block_header: '$' block_name ';'
44             {$item[2];}
45              
46             block_content: comment | statement_ref | statement_def | statement_scan | parameter_assignment
47              
48             statement_ref: 'ref' reference '=' parameter_values ';'
49             {new Astro::VEX::Ref($item[2], $item[4]);}
50              
51             statement_def: 'def' identifier ';' def_content(s?) 'enddef' ';'
52             {new Astro::VEX::Def($item[2], $item[4]);}
53              
54             def_content: comment | statement_ref | parameter_assignment
55              
56             statement_scan: 'scan' identifier ';' scan_content(s?) 'endscan' ';'
57             {new Astro::VEX::Scan($item[2], $item[4]);}
58              
59             scan_content: comment | parameter_assignment
60              
61             parameter_assignment: parameter_name '=' parameter_values ';'
62             {new Astro::VEX::Param($item[1], $item[3]);}
63              
64             parameter_values: parameter_value parameter_values_tail(s?)
65             {my $tail = $item[2]->[0]; [$item[1], ref $tail ? @$tail : ()];}
66              
67             parameter_values_tail: ':' parameter_values
68             {$item[2];}
69              
70             parameter_value: parameter_value_link | parameter_value_number_with_unit | parameter_value_number_without_unit | parameter_value_plain | parameter_value_quoted | parameter_value_empty
71              
72             block_name: /[!"#$%&'()*+,\\-.\/0-9:<>?\@A-Z\\[\\\\\\]^_`a-z{|}~]+/
73              
74             reference: '$' block_name
75             {$item[2];}
76              
77             parameter_name: ...!/[$&*"]/ /[!"#$%&'()*+,\\-.\/0-9<>?\@A-Z\\[\\\\\\]^_`a-z{|}~]+/
78              
79             parameter_value_link: '&' /[!"#$%&'()*+,\\-.\/0-9<>?\@A-Z\\[\\\\\\]^_`a-z{|}~]+/
80             {new Astro::VEX::Link($item[2]);}
81              
82             parameter_value_plain: ...!/["$&]/ /[!"#$%&'()+,\\-.\/0-9<=>?\@A-Z\\[\\\\\\]^_`a-z{|}~\\n\\t]+/
83             {new Astro::VEX::Param::String($item[2] =~ s/[\n\t ]+$//r, 0)}
84              
85             parameter_value_quoted: '"' parameter_value_quoted_char(s?) '"'
86             {new Astro::VEX::Param::String((join '', @{$item[3]}), 1)}
87              
88             parameter_value_quoted_char: parameter_value_quoted_char_plain | parameter_value_quoted_char_escape
89              
90             parameter_value_quoted_char_plain: /[ !#$%&'()*+,\\-.\/0-9:;<=>?\@A-Z\\[\\]^_`a-z{|}~\\n\\t]/
91              
92             parameter_value_quoted_char_escape: '\\\\' /["'?\\\\]/
93             {$item[2]}
94              
95             parameter_value_empty: '' .../[:;]/
96             {new Astro::VEX::Param::Empty()}
97              
98             parameter_value_number_with_unit: parameter_value_number_plain parameter_value_unit .../[:;]/
99             {new Astro::VEX::Param::Number($item[1], $item[2])}
100              
101             parameter_value_number_without_unit: parameter_value_number_plain .../[:;]/
102             {new Astro::VEX::Param::Number($item[1], undef)}
103              
104             parameter_value_number_plain: /[-+]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+))(?:[Ee][-+]?[0-9]+)?/
105              
106             parameter_value_unit: parameter_value_unit_angrate | parameter_value_unit_velocity | parameter_value_unit_time | parameter_value_unit_freq | parameter_value_unit_rate | parameter_value_unit_length | parameter_value_unit_angle | parameter_value_unit_flux | parameter_value_unit_bitdens | parameter_value_unit_flsz
107              
108             parameter_value_unit_angrate: parameter_value_unit_angle '/' parameter_value_unit_time
109             {$item[1] . '/' . $item[3]}
110             parameter_value_unit_velocity: parameter_value_unit_length '/' parameter_value_unit_time
111             {$item[1] . '/' . $item[3]}
112              
113             parameter_value_unit_time: 'psec' | 'nsec' | 'usec' | 'msec' | 'sec' | 'min' | 'hr' | 'yr'
114             parameter_value_unit_freq: 'mHz' | 'Hz' | 'kHz' | 'MHz' | 'GHz'
115             parameter_value_unit_rate: 'ks/sec' | 'Ms/sec'
116             parameter_value_unit_length: 'um' | 'mm' | 'cm' | 'm' | 'km' | 'in' | 'ft'
117             parameter_value_unit_angle: 'mdeg' | 'deg' | 'amin' | 'asec' | 'rad'
118             parameter_value_unit_flux: 'mJy' | 'Jy'
119             parameter_value_unit_bitdens: 'bpi' | 'kbpi'
120             parameter_value_unit_flsz: 'MB' | 'GB' | 'TB'
121              
122             identifier: /[!"#%'()+,\\-.\/0-9<>?\@A-Z\\[\\\\\\]^_`a-z{|}~]+/
123              
124             # Example (not used).
125             anychar: /[ !"#$%&'()*+,\\-.\/0-9:;<=>?\@A-Z\\[\\\\\\]^_`a-z{|}~]/
126             };
127              
128              
129             sub parse_vex {
130 1     1 0 2 my $cls = shift;
131 1         2 my $text = shift;
132              
133 1 50       7 my $parser = new Parse::RecDescent($grammar)
134             or die 'Failed to prepare parser';
135              
136             # Parse text as reference so that we are left with whatever didn't match.
137 1         193467 my $result = $parser->vex(\$text);
138              
139 1         55 chomp $text;
140 1         2 $text =~ s/^\s//;
141 1         2 $text =~ s/\s$//;
142 1 50       3 die "Failed to parse VEX at: '" . (substr $text, 0, 60) . "'"
143             if $text;
144              
145 1         7 return $result;
146             }
147              
148             1;
149              
150             __END__