File Coverage

blib/lib/Repl/Loop.pm
Criterion Covered Total %
statement 18 83 21.6
branch 0 18 0.0
condition 0 8 0.0
subroutine 6 17 35.2
pod 1 11 9.0
total 25 137 18.2


line stmt bran cond sub pod time code
1             package Repl::Loop;
2            
3             our $VERSION = '1.00';
4            
5 1     1   1343 use strict;
  1         2  
  1         32  
6 1     1   5 use warnings;
  1         1  
  1         26  
7            
8 1     1   4 use Repl::Core::Parser;
  1         2  
  1         26  
9 1     1   6 use Repl::Core::Eval;
  1         2  
  1         24  
10            
11 1     1   6 use constant PROMPT_NORMAL => "> ";
  1         3  
  1         99  
12 1     1   6 use constant PROMPT_CONTINUE => "+ > ";
  1         4  
  1         989  
13            
14             sub new
15             {
16 0     0 0   my $invocant = shift;
17 0   0       my $class = ref($invocant) || $invocant;
18            
19 0           my $self= {};
20 0           $self->{PARSER} = new Repl::Core::Parser();
21 0           $self->{EVAL} = new Repl::Core::Eval();
22 0           $self->{STOPREQUESTED} = 0;
23 0           $self->{PROMPT} = PROMPT_NORMAL;
24 0           $self->{CURRCMD} = "";
25 0           return bless $self, $class;
26             }
27            
28             sub start
29             {
30 0     0 0   my $self = shift;
31 0           while(!$self->{STOPREQUESTED})
32             {
33 0           print $self->{PROMPT};
34 0   0       my $line = || '';
35 0           $self->handleLine($line);
36             }
37 0           $self->{STOPREQUESTED} = 0;
38             }
39            
40             sub stop
41             {
42 0     0 0   my $self = shift;
43 0           $self->{STOPREQUESTED} = 1;
44             }
45            
46             sub handleLine
47             {
48 0     0 0   my $self = shift;
49 0           my $line = shift;
50            
51 0 0 0       return if(!$line || $line =~ /^\s*$/);
52 0 0         if($line =~ /\s*break\s*/i)
53             {
54 0           $self->recover();
55 0           print "Canceling the command.\n";
56 0           return;
57             }
58            
59 0 0         if($line =~ /^(.+)\\$/)
60             {
61             # The line ends with a backslash (line continuation).
62 0           $self->{CURRCMD} = $self->{CURRCMD} . $1;
63 0           $self->{PROMPT} = PROMPT_CONTINUE;
64             }
65             else
66             {
67 0           my $expr = $self->{CURRCMD} . $line;
68 0           $self->{CURRCMD} = $expr;
69            
70 0 0         if(!($expr =~ /\A\s*\(.+\)\s*\Z/s ))
71             {
72 0           $expr = "(" . $expr . ")";
73             }
74            
75 0           my $parsed = $self->{PARSER}->parseString($expr);
76 0 0         if(ref($parsed) eq "ARRAY")
    0          
77             {
78 0           $self->recover();
79 0           eval {$self->{EVAL}->evalExpr($parsed)};
  0            
80 0 0         print cutat($@) if($@);
81             }
82             elsif (ref($parsed) eq "Repl::Core::Token")
83             {
84 0 0         if($parsed->isEof())
85             {
86 0           $self->{PROMPT} = PROMPT_CONTINUE;
87             }
88             else
89             {
90 0           print $parsed->getValue() . "\n";
91 0           $self->recover();
92             }
93             }
94             else
95             {
96 0           $self->recover();
97             }
98             }
99             }
100            
101             # Ordinary function, not a method.
102             # Cut of the "at ." part of the error message.
103             sub cutat
104             {
105 0     0 0   my $msg = shift;
106             # Note the 's' regexp option to allow . to match newlines.
107 0 0         if($msg =~ /\A(.*) at .+ line .*\Z/s)
108             {
109             # Cut of the "at line dddd." part.
110             # Because it will always point to this location here.
111 0           $msg = $1 . "\n";
112             }
113 0           return $msg;
114             }
115            
116             sub recover
117             {
118 0     0 0   my $self = shift;
119 0           $self->{CURRCMD} = "";
120 0           $self->{PROMPT} = PROMPT_NORMAL;
121             }
122            
123             # Two parameters:
124             # - A name
125             # - A command instance.
126             sub registerCommand
127             {
128 0     0 0   my $self = shift;
129 0           my $name = shift;
130 0           my $cmd = shift;
131 0           $self->{EVAL}->registerCommand($name, $cmd);
132             }
133            
134             # Two parameters:
135             # - A name
136             # - A command instance.
137             sub registerMacro
138             {
139 0     0 0   my $self = shift;
140 0           my $name = shift;
141 0           my $cmd = shift;
142 0           $self->{EVAL}->{MACREPO}->registerMacro($name, $cmd);
143             }
144            
145             # One parameter
146             # An expression that will be evaluated in the repl.
147             # Can be useful to add pre-defined functions to the eval.
148             # Single string argument.
149             sub eval
150             {
151 0     0 1   my $self = shift;
152 0           my $expr = shift;
153            
154 0           return $self->{EVAL}->evalExpr($self->{PARSER}->parseString($expr));
155             }
156            
157             # Single parsed expression argument.
158             sub evalExpr
159             {
160 0     0 0   my $self = shift;
161 0           my $expr = shift;
162            
163 0           return $self->{EVAL}->evalExpr($expr);
164             }
165            
166             # Get the internal eval.
167             sub getEval
168             {
169 0     0 0   my $self = shift;
170 0           return $self->{EVAL};
171             }
172            
173             1;
174            
175             __END__