File Coverage

blib/lib/Data/Stag/SxprParser.pm
Criterion Covered Total %
statement 81 94 86.1
branch 37 54 68.5
condition n/a
subroutine 8 9 88.8
pod 0 2 0.0
total 126 159 79.2


line stmt bran cond sub pod time code
1             # $Id: SxprParser.pm,v 1.22 2008/06/03 17:31:15 cmungall Exp $
2             #
3             # Copyright (C) 2002 Chris Mungall
4             #
5             # See also - http://stag.sourceforge.net
6             #
7             # This module is free software.
8             # You may distribute this module under the same terms as perl itself
9              
10             package Data::Stag::SxprParser;
11              
12             =head1 NAME
13              
14             SxprParser.pm - parses Stag S-expression format
15              
16             =head1 SYNOPSIS
17              
18             =cut
19              
20             =head1 DESCRIPTION
21              
22              
23             =head1 AUTHOR
24              
25             =cut
26              
27 4     4   24 use Exporter;
  4         7  
  4         202  
28 4     4   23 use Carp;
  4         8  
  4         257  
29 4     4   26 use FileHandle;
  4         5  
  4         64  
30 4     4   2093 use strict;
  4         10  
  4         193  
31 4     4   26 use Data::Stag qw(:all);
  4         7  
  4         4416  
32 4     4   32 use base qw(Data::Stag::BaseGenerator Exporter);
  4         9  
  4         2493  
33              
34 4     4   33 use vars qw($VERSION);
  4         8  
  4         3220  
35             $VERSION="0.14";
36              
37             sub fmtstr {
38 0     0 0 0 return 'sxpr';
39             }
40              
41             sub parse_fh {
42 7     7 0 15 my $self = shift;
43 7         11 my $fh = shift;
44 7         14 my $line_no = 0;
45 7         10 my $state = "init";
46 7         12 my $txt = '';
47              
48             # c: comment ;
49             # q: quote (double quote only)
50             # o: opening tag - after round bracket, before whitespace or ()
51             # 0: body, or awaiting open or close
52 7         89 while (my $line = <$fh>) {
53 105         1346 $line_no++;
54              
55 105         216 while (length($line)) {
56 1956         2892 my $c = substr($line,0,1,'');
57 1956 100       3795 if ($state eq 'init') {
58 11 100       37 if ($c eq '(') {
    50          
    0          
    0          
59             # at start - do nothing
60 7         15 $state = 0;
61             }
62             elsif ($c eq "'") {
63             # leading quote is allowed [list constructor in lisp]
64             # (good for editing in emacs)
65 4         24 next;
66 0         0 $state = 0;
67             }
68             elsif ($c =~ /\s/) {
69 0         0 next;
70             }
71             elsif ($c eq ';') {
72 0         0 $state = 'c';
73             }
74             else {
75 0         0 $self->throw("Line: $line_no\n$line\nExpected \"(\" at start of file");
76             }
77             }
78 1952 50       3517 $state ne 'init' || $self->throw("assertion error: state=$state");
79            
80 1952 50       3345 if ($state eq 'c') { # comment
81             # newline is the only char that can break out of comments
82 0 0       0 if ($c eq "\n") {
83 0         0 $state = 0;
84             }
85 0         0 next;
86             }
87 1952 50       3236 $state ne 'c' || $self->throw("assertion error: state=$state");
88            
89 1952 100       20271 if ($state eq 'q') {
90 465 100       802 if ($c eq '"') {
91 62         76 $state = 0;
92             }
93             else {
94 403         416 $txt .= $c;
95             }
96 465         827 next;
97             }
98 1487 50       2834 $state ne 'q' || $self->throw("assertion error: state=$state");
99            
100 1487 100       2589 if ($c eq '"') {
101 62         76 $state = 'q';
102 62         124 next;
103             }
104 1425 50       2724 $state ne 'q' || $self->throw("assertion error: state=$state");
105            
106 1425 50       2506 if ($c eq ';') {
107             # can only open comments when NOT in quotes
108 0         0 $state = 'c';
109 0         0 next;
110             }
111            
112 1425 100       2355 if ($c eq '(') {
113 110 100       199 if ($state eq 'o') {
114 6 50       14 if (!$txt) {
115 0         0 $self->throw("Line: $line_no\b$line\ndouble open brackets (( not allowed!");
116             }
117 6         31 $self->start_event($txt);
118 6         8 $txt = '';
119             }
120 110         217 $state = 'o';
121 110         532 next;
122             }
123 1315 100       2216 if ($c eq ')') {
124 110 100       516 if ($state eq 'o') {
125 1 50       2 if (!$txt) {
126 0         0 $self->throw("Line: $line_no\b$line\n () not allowed!");
127             }
128 1         5 $self->start_event($txt);
129 1         1 $txt = '';
130 1         6 $self->end_event;
131             }
132             else {
133 109 100       193 if ($txt) {
134 66         195 $self->evbody($txt);
135             }
136 109         140 $txt = '';
137 109         321 $self->end_event;
138             }
139 110         130 $state=0;
140 110         260 next;
141             }
142 1205 100       2534 if ($state eq 'o') {
143 759 100       1509 if ($c =~ /\s/) {
144             # reached last char of start event name
145 103         366 $self->start_event($txt);
146 103         130 $txt = '';
147 103         105 $state = 0;
148 103         375 next;
149             }
150             else {
151 656         698 $txt .= $c;
152 656         1315 next;
153             }
154             }
155 446 50       936 $state == 0 || $self->throw("assertion error: state=$state");
156 446 100       1719 if ($c =~ /\s/) {
157 442         1103 next;
158             }
159 4         7 $txt .= $c;
160 4         10 next;
161             }
162             }
163 7 50       86 if ($txt =~ /\S/) {
164 0           $self->throw("text at end: $txt");
165             }
166             }
167              
168             1;