File Coverage

blib/lib/Shishi/Prototype.pm
Criterion Covered Total %
statement 29 81 35.8
branch 2 40 5.0
condition 0 3 0.0
subroutine 10 12 83.3
pod 0 7 0.0
total 41 143 28.6


line stmt bran cond sub pod time code
1              
2             # Flaws: action code and decision code not separated.
3              
4             package Shishi::Prototype;
5             $Shishi::Debug = 0;
6             1;
7             package Shishi;
8 1     1   5 use strict;
  1         1  
  1         36  
9 1     1   583 use Shishi::Node;
  1         3  
  1         30  
10 1     1   14 use Shishi::Decision;
  1         2  
  1         140  
11 1     1   6 use Exporter;
  1         2  
  1         1593  
12             @Shishi::ISA = qw( Exporter );
13             @Shishi::EXPORT_OK = qw( ACTION_FINISH ACTION_REDUCE ACTION_CODE
14             ACTION_SHIFT ACTION_CONTINUE ACTION_FAIL);
15              
16             sub new {
17 1     1 0 136 my $self = shift;
18 1         8 my $o = bless {
19             creator => shift,
20             decisions => [],
21             nodes => [],
22             stack => [],
23             };
24             # We start with one node
25 1         17 $o->add_node(new Shishi::Node ($o->{creator}));
26 1         3 return $o;
27             }
28              
29             sub new_mo {
30 4     4 0 22 bless {
31             text => $_[1]
32             }, "Shishi::Match";
33             }
34              
35             sub add_node {
36 3     3 0 5 my $self = shift;
37 3         5 my $node = shift;
38 3         7 $node->{parents}++;
39 3         4 push @{$self->{nodes}}, $node;
  3         7  
40 3         5 return $self;
41             }
42              
43             sub execute {
44 4     4 0 8 my $self = shift;
45 4         5 my $text = shift;
46 4         8 $self->start_node->execute($self, Shishi->new_mo($text)) > 0;
47             }
48              
49 7     7 0 33 sub start_node { $_[0]->{nodes}->[0] }
50              
51 35 100   35   38 sub Shishi::Match::parse_text { my $self = shift; @_ ? $self->{text} = shift : $self->{text}; }
  35         114  
52              
53             sub dump {
54 0     0 0   my $parser = shift;
55 0           print "Parser ".$parser->{creator}." dump\n";
56 0           my %name2num;
57 0           my @nodes = @{$parser->{nodes}};
  0            
58 0           print ((scalar @nodes), " nodes\n\n");
59 0           $name2num{$nodes[$_]}=$_ for 0..$#nodes;
60 0           for (0..$#nodes) {
61 0           my $n = $nodes[$_];
62 0           print "$_:\n";
63 0           for ($n->decisions) {
64 0           print "\tMatch ".$_->{type}.":";
65 0 0         print " ".$_->{target} if exists $_->{target};
66 0           print " -> ";
67 0 0         print "($_->{hint}) " if exists $_->{hint};
68 0 0         if ($_->{action} == ACTION_FINISH) {
    0          
    0          
    0          
    0          
    0          
69 0           print "DONE\n";
70             } elsif ($_->{action} == ACTION_FAIL) {
71 0           print "FAIL\n";
72             } elsif ($_->{action} == ACTION_CONTINUE) {
73 0 0         if (defined $_->{next_node}) {
74 0 0         print exists $name2num{$_->{next_node}} ?
75             $name2num{$_->{next_node}}
76             :
77             "UNKNOWN NODE ($_->{next_node})\n";
78 0           } else { print "INCOMPLETE" }
79 0           print "\n";
80             } elsif ($_->{action} == ACTION_SHIFT) {
81 0           print "SHIFT (something)\n";
82             } elsif ($_->{action} == ACTION_REDUCE) {
83 0           print "REDUCE\n";
84             } elsif ($_->{action} == ACTION_CODE) {
85 0           print "CODE (".$_->{code}.")\n";
86             } else {
87 0           print "UNKNOWN ACTION\n";
88             }
89             }
90             }
91             }
92              
93             sub as_dot {
94 0     0 0   require GraphViz;
95 0           my $g = GraphViz->new(rankdir => "LR");
96 0           my $parser = shift;
97 0           my @nodes = @{$parser->{nodes}};
  0            
98 0           $g->add_node($_, shape=>"circle") for 0..$#nodes;
99 0           my %name2num;
100 0           $name2num{$nodes[$_]}=$_ for 0..$#nodes;
101 0           for my $node_num (0..$#nodes) {
102 0           my $n = $nodes[$node_num];
103 0           for ($n->decisions) {
104 0 0 0       my $dec = $g->add_node(
105             label => "$_->{type}".(
106             exists $_->{target} ? " ($_->{target}) " :
107             (exists $_->{code} && " ($_->{code}) ")
108             ),
109             shape => "box"
110             );
111 0 0         $g->add_edge($node_num, $dec, (exists $_->{hint} ? (label => $_->{hint}) : ()));
112 0 0         if ($_->{action} == ACTION_FINISH) {
    0          
    0          
    0          
    0          
    0          
113 0           my $targ = $g->add_node(
114             label => "DONE", style => "bold", shape => "circle");
115 0           $g->add_edge($dec, $targ);
116             } elsif ($_->{action} == ACTION_FAIL) {
117 0           my $targ = $g->add_node(
118             label => "FAIL", style => "bold", shape => "circle");
119 0           $g->add_edge($dec, $targ);
120             } elsif ($_->{action} == ACTION_SHIFT) {
121 0           my $targ = $g->add_node(
122             label => "SHIFT", style => "bold", shape => "circle");
123 0           $g->add_edge($dec, $targ);
124             } elsif ($_->{action} == ACTION_REDUCE) {
125 0           my $targ = $g->add_node(
126             label => "REDUCE", style => "bold", shape => "circle");
127 0           $g->add_edge($dec, $targ);
128             } elsif ($_->{action} == ACTION_CONTINUE) {
129 0 0         $g->add_edge($dec, exists $name2num{$_->{next_node}} ?
130             $name2num{$_->{next_node}} : $_->{next_node});
131             } elsif ($_->{action} == ACTION_CODE) {
132 0           my $targ = $g->add_node(
133             label => "CODE", style => "bold", shape => "circle");
134 0           $g->add_edge($dec, $targ);
135             }
136             }
137             }
138 0           return $g->_as_debug;
139             }
140              
141             1;
142              
143             =head1 NAME
144              
145             Shishi::Prototype - Internal use prototype for the Shishi regex/parser
146              
147             =head1 SYNOPSIS
148              
149             my $parser = new Shishi ("test parser");
150             $parser->start_node->add_decision(
151             new Shishi::Decision(target => 'a', type => 'char', action => 4,
152             next_node => Shishi::Node->new->add_decision(
153             new Shishi::Decision(target => 'b', type => 'char', action => 4,
154             next_node => Shishi::Node->new->add_decision(
155             new Shishi::Decision(target => 'c', type => 'char', action => 0)
156             ))
157             ))
158             );
159             $parser->start_node->add_decision(
160             new Shishi::Decision(type => 'skip', next_node => $parser->start_node,
161             action => 4)
162             );
163             $parser->parse_text("babdabc");
164             if ($parser->execute()) {
165             print "Successfully matched\n"
166             } else {
167             print "Match failed\n";
168             }
169              
170             =head1 DESCRIPTION
171              
172             This is a prototype only. The real library (C) will come once
173             this prototype is finalised. The interface will remain the same.
174              
175             As this is only a prototype, don't try doing anything with it yet.
176             However, feel free to use Shishi applications such as
177             C.
178              
179             When C itself is released, you can uninstall this module and
180             install C and everything ought to work as normal. (Except
181             perhaps somewhat faster.) However, since we're still firming up the
182             interface with this prototype, it's best not to depend on it; hence, the
183             interface is not currently documented.
184              
185             =head1 AUTHOR
186              
187             Simon Cozens, C
188              
189             =cut