Changeset 3480
- Timestamp:
- Mar 22, 2005, 4:00:16 PM (21 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/PS-IPP-Metadata-Config/lib/PS/IPP/Metadata/Config.pm
r3457 r3480 1 1 # Copyright (c) 2005 Joshua Hoblitt 2 2 # 3 # $Id: Config.pm,v 1. 8 2005-03-19 01:01:46 jhoblitt Exp $3 # $Id: Config.pm,v 1.9 2005-03-23 02:00:16 jhoblitt Exp $ 4 4 5 5 package PS::IPP::Metadata::Config; … … 46 46 47 47 #print Dumper($tree); 48 49 # handle multi-symbol lines50 $self->_merge_multi_symbols( $tree ) or return undef;51 52 # look for duplicate names, there should be none after processing the53 # multi-symbols54 $self->_merge_duplicates( $tree ) or return undef;55 48 56 49 return $tree; 57 50 } 58 51 59 sub _merge_multi_symbols {60 my ( $self, $tree ) = @_;61 62 # list of valid multi-symbols63 my %multis;64 65 # Iteratate through the parse tree looking for multi-symbol66 # declarations. This is done in a single pass so multi-symbols must67 # actually be 'declared' before any member elements appear.68 for (my $i = 0; $i < @{$tree}; $i++) {69 my $elem = $tree->[$i];70 71 # recurse through nested metadata72 if ( $elem->{class} eq "metadata" ) {73 $self->_merge_multi_symbols( $elem->{value} );74 }75 76 # stop if the prevous pass removed the last element and called redo77 last unless defined $elem;78 79 if ( $elem->{class} eq "multi_symbol" ) {80 # construct a valid parse spec81 my $node = {82 class => 'vector',83 name => $elem->{name},84 type => 'STR', # only strings are allowed85 value => [],86 };87 88 # add to list of valid multi-symbols89 $multis{ $elem->{name} } = $node;90 91 # delete multi-symbol hash from the parse tree and replace it92 splice @$tree, $i, 1, $node;93 94 next;95 }96 97 if ( my $node = $multis{ $elem->{name} } ) {98 if ( ! $elem->{type} =~ /STR|STRING/ ) {99 carp "multi-symbol element, ",100 $elem->{name},101 "has type of ",102 $elem->{type},103 "instead of STR|STRING\n";104 return undef;105 }106 107 # add element value to the appropriate multi-symbol element108 my $vec = $node->{value};109 push( @$vec, $elem->{value} );110 111 # delete element from array112 splice @$tree, $i, 1;113 114 # the list just got shorter by one element so we don't want to115 # increment the cursor116 redo;117 }118 }119 120 return 1;121 }122 123 sub _merge_duplicates {124 my ( $self, $tree ) = @_;125 126 # encountered names127 my %names;128 129 # Iteratate through the parse tree looking for duplicate declarations and130 # resolving them by discarding elements according to the value of 'overwrite'.131 for (my $i = 0; $i < @{$tree}; $i++) {132 my $elem = $tree->[$i];133 134 # recurse through nested metadata135 if ( $elem->{class} eq "metadata" ) {136 $self->_merge_duplicates( $elem->{value} );137 }138 139 if ( exists $names{ $elem->{name} } ) {140 carp "duplicate element name, ", $elem->{name}, "\n";141 142 if ( $self->{overwrite} ) {143 # remove the previous occurance144 splice @{$tree}, $names{ $elem->{name} }, 1;145 } else {146 # remove the current occurance147 splice @{$tree}, $i, 1;148 }149 }150 151 # add element name and location to record of previously seen names152 $names{ $elem->{name} } = $i;153 }154 155 return 1;156 }157 158 52 1; 159 53 … … 162 56 { 163 57 use strict; 164 use warnings FATAL => qw( all ); 165 166 use Carp qw( croak ); 58 59 use Carp qw( carp ); 60 61 our @scope_stack; 167 62 } 168 63 169 startrule: grammar 64 startrule: grammar eofile 65 { $item{grammar} } 170 66 171 67 grammar: 172 68 statement(s) 173 {[ grep $_->{class} !~ /(comment_line|blank_line)/, @{$item[1]} ]} 69 { 70 $thisparser->{local} = pop @scope_stack; 71 [ grep $_->{class} !~ /(comment_line|blank_line)/, @{$item[1]} ]; 72 } 174 73 175 74 statement: 176 75 scalar 177 76 | vector 178 | multi_ symbol77 | multi_declare 179 78 | comment_line 180 79 | metadata 181 80 | blank_line 81 | time 182 82 | typedef_declare 183 83 | typedef 84 | <error:unmatched statement: $text> 184 85 185 86 scalar: 186 <skip:'[ \t\r]*'> name type value comment "\n" 187 {{ 188 class => 'scalar', 189 name => $item{name}, 190 type => $item{type}, 191 value => $item{value}, 192 comment => $item{comment} 193 }} 194 | <skip:'[ \t\r]*'> name type value "\n" 195 {{ 196 class => 'scalar', 197 name => $item{name}, 198 type => $item{type}, 199 value => $item{value}, 200 }} 87 <skip:'[ \t\r]*'> name type value comment(?) "\n" 88 { 89 $return = { 90 class => 'scalar', 91 name => $item{name}, 92 type => $item{type}, 93 value => $item{value}, 94 }; 95 96 $return->{comment} = $item{'comment(?)'}[0] 97 if $item{'comment(?)'}[0]; 98 } 201 99 202 100 vector: 203 <skip:'[ \t\r]*'> vname vtype vvalue comment "\n" 204 {{ 205 206 class => 'vector', 207 name => $item{vname}, 208 type => $item{vtype}, 209 value => $item{vvalue}, 210 comment => $item{comment} 211 }} 212 | <skip:'[ \t\r]*'> vname vtype vvalue "\n" 213 {{ 214 class => 'vector', 215 name => $item{vname}, 216 type => $item{vtype}, 217 value => $item{vvalue}, 218 }} 219 220 multi_symbol: 101 <skip:'[ \t\r]*'> vname vtype vvalue comment(?) "\n" 102 { 103 $return = { 104 class => 'vector', 105 name => $item{vname}, 106 type => $item{vtype}, 107 value => $item{vvalue}, 108 comment => $item{comment} 109 }; 110 111 $return->{comment} = $item{'comment(?)'}[0] 112 if $item{'comment(?)'}[0]; 113 } 114 115 multi_declare: 221 116 <skip:'[ \t\r]*'> name '*' to_end_of_line "\n" 222 117 {{ 223 class => 'multi_symbol', 224 name => $item{name}, 225 comment => $item{to_end_of_line}, 118 class => 'blank_line', 226 119 }} 227 120 … … 234 127 235 128 metadata: 236 metadata_name grammar metadata_end 237 {{ 238 class => 'metadata', 239 name => $item{metadata_name}, 240 value => $item{grammar}, 241 }} 129 metadata_name <commit> 130 { push @scope_stack, $thisparser->{local}; $thisparser->{local} = {} } 131 grammar 132 metadata_end 133 { 134 my $text = $item[2]; 135 136 if ( defined( $text ) ) { 137 $return = { 138 class => 'metadata', 139 name => $item{metadata_name}, 140 value => $item{grammar}, 141 }; 142 } else { 143 $return = undef; 144 } 145 } 146 | <error?:bad METADATA syntax: $text> <reject> 242 147 243 148 blank_line: … … 247 152 }} 248 153 154 time: 155 <skip:'[ \t\r]*'> name ttype <matchrule:$item{ttype}> comment(?) "\n" 156 { 157 use DateTime::Format::ISO8601; 158 159 $return = { 160 class => 'time', 161 name => $item{name}, 162 type => $item{ttype}, 163 value => $item[4], 164 }; 165 166 $return->{comment} = $item{'comment(?)'}[0] 167 if $item{'comment(?)'}[0]; 168 } 169 249 170 typedef_declare: 250 171 <skip:'[ \t\r]*'> 'TYPE' <commit> name name(s) comment(?) "\n" 251 172 { 252 use Carp;253 254 173 if (defined $thisparser->{local}{typedef}{ $item{name} }) { 255 croak "refinition of TYPE $item{name}"; 256 } 257 258 my $type = { 259 class => 'typedef_declare', 260 name => $item{name}, 261 fields => $item{'name(s)'}, 262 length => scalar @{ $item{'name(s)'} }, 263 }; 264 265 $thisparser->{local}{typedef}{ $item{name} } = $type; 266 267 # don't return anything in the parse tree 268 $return = { class => 'blank_line' }; 269 } 174 carp "refinition of TYPE $item{name}"; 175 $return = undef; 176 } else { 177 178 my $type = { 179 class => 'typedef_declare', 180 name => $item{name}, 181 fields => $item{'name(s)'}, 182 length => scalar @{ $item{'name(s)'} }, 183 }; 184 185 $thisparser->{local}{typedef}{ $item{name} } = $type; 186 187 # don't return anything in the parse tree 188 $return = { class => 'blank_line' }; 189 } 190 } 191 | <error?:redefinition of TYPE> <reject> 270 192 271 193 typedef: 272 <skip:'[ \t\r]*'> name typedef_type name(s) comment(?) "\n"194 <skip:'[ \t\r]*'> name typedef_type <commit> name(s) comment(?) "\n" 273 195 { 274 196 my $type = $thisparser->{local}{typedef}{ $item{typedef_type} }; 275 197 276 198 unless ( scalar @{ $item{'name(s)'} } == $type->{length} ) { 277 c roak"\"$item{name} $item{typedef_type}\""199 carp "\"$item{name} $item{typedef_type}\"" 278 200 . " does not have enough fields"; 279 } 280 281 my @md; 282 my $i = 0; 283 foreach my $name ( @{ $type->{fields} } ) { 284 push @md, { 285 name => $name, 286 class => 'scalar', 287 type => 'STR', 288 value => $item{'name(s)'}[$i], 201 $return = undef; 202 } else { 203 my @md; 204 my $i = 0; 205 foreach my $name ( @{ $type->{fields} } ) { 206 push @md, { 207 name => $name, 208 class => 'scalar', 209 type => 'STR', 210 value => $item{'name(s)'}[$i], 211 }; 212 213 $i++; 214 } 215 216 $return = { 217 class => 'metadata', 218 name => $item{name}, 219 value => \@md, 289 220 }; 290 291 $i++; 292 } 293 294 $return = { 295 class => 'metadata', 296 name => $item{name}, 297 value => \@md, 298 }; 299 } 221 } 222 } 223 | <error?:'TYPE' does not have enough parameters: $text> <reject> 224 300 225 301 226 typedef_type: name 302 227 { 303 use Carp;304 305 228 if ( ! defined $thisparser->{local}{typedef}{ $item{name} } ) { 306 croak "missing TYPE defintion for $item{name}"; 307 } 308 $return = $item{name}; 229 $return = undef; 230 } else { 231 $return = $item{name}; 232 } 309 233 } 310 234 … … 352 276 | 'BOOL' 353 277 278 ttype: 279 'UTC' 280 | 'UT1' 281 | 'TAI' 282 | 'TT' 283 354 284 value: 355 285 primitive | string … … 359 289 _vvalue(s) 360 290 { [ map { @$_ } @{$item[1]} ] } 291 292 tvalue: 293 iso8601 294 | epoch 361 295 362 296 # backtracking optimization … … 384 318 385 319 string: 386 / \S[^#\n]*/320 /(?:\S[^#\n]*)?[^#\n ]/ 387 321 388 322 to_end_of_line: 389 323 /[^\n]*/ 324 { 325 my $comment = $item[1]; 326 # remove leading whitespace 327 $comment =~ s/^\s+//; 328 # remove trailing whitespace 329 $comment =~ s/\s+$//; 330 331 $return = $comment; 332 } 333 334 UTC: 335 iso8601 336 | utc_epoch 337 338 UT1: 339 iso8601 340 | epoch 341 342 TAI: 343 iso8601 344 | epoch 345 346 TT: 347 iso8601 348 | epoch 349 350 iso8601: 351 # based on code from DateTime::Format::ISO8601 352 / (\d{4}) - (\d\d) - (\d\d) T (\d\d) : (\d\d) : (\d\d) Z /x 353 { DateTime::Format::ISO8601->parse_datetime( $item[1] ) } 354 355 utc_epoch: 356 / (-?\d{1,19}) \s*,\s* (\d{1,9}) (?:\s*,\s* (\d))? /x 357 {{ 358 sec => $1, 359 nsec => $2, 360 leapsecond => $3, 361 }} 362 363 epoch: 364 / (-?\d{1,19}) \s*,\s* (\d{1,9}) /x 365 {{ 366 sec => $1, 367 nsec => $2, 368 }} 369 370 eofile: 371 /^\z/
Note:
See TracChangeset
for help on using the changeset viewer.
