File Coverage

blib/lib/Anarres/Mud/Driver/Program/Method.pm
Criterion Covered Total %
statement 18 88 20.4
branch 0 20 0.0
condition n/a
subroutine 6 14 42.8
pod 0 8 0.0
total 24 130 18.4


line stmt bran cond sub pod time code
1             package Anarres::Mud::Driver::Program::Method;
2              
3 4     4   19 use strict;
  4         9  
  4         126  
4 4     4   19 use vars qw(@ISA @EXPORT);
  4         6  
  4         160  
5 4     4   44 use Data::Dumper;
  4         6  
  4         171  
6 4     4   19 use Carp qw(cluck);
  4         6  
  4         192  
7 4     4   18 use Anarres::Mud::Driver::Program::Variable;
  4         8  
  4         130  
8 4     4   17 use Anarres::Mud::Driver::Compiler::Type qw(:all);
  4         5  
  4         5233  
9              
10             @ISA = qw(Anarres::Mud::Driver::Program::Variable);
11             *EXPORT = \@Anarres::Mud::Driver::Program::Variable::EXPORT;
12              
13 0     0 0   sub args { return $_[0]->{Args}; }
14              
15             # Code is added later in the parser (was?)
16             sub code {
17 0     0 0   my ($self, $code) = @_;
18             # cluck "Add code $code to method $self->{Name}\n" if $code;
19 0 0         if (defined $code) {
20 0           $self->{Code} = $code;
21             # print Dumper($code);
22             }
23 0           return $self->{Code};
24             }
25              
26             sub check {
27 0     0 0   my ($self, $program, @rest) = @_;
28             # print "Typechecking method " . $self->name . " (top level)\n";
29             # print $self->dump, "\n";
30              
31             # Start adding locals, etc, etc.
32              
33 0           $program->reset_labels;
34 0           $program->save_locals;
35 0           foreach (@{ $self->args }) {
  0            
36 0           $program->local($_->name, $_);
37             }
38 0           my $code = $self->code;
39 0 0         if ($code) {
40 0           $code->check($program, @rest);
41             }
42             else {
43 0           $program->error("No code in method " . $self->name);
44             }
45 0           $program->restore_locals;
46             # print $self->dump, "\n";
47             }
48              
49             sub dump {
50 0     0 0   my $self = shift;
51 0           my $indent = shift;
52 0           $indent++;
53              
54 0           my $sep = "\n" . ("\t" x $indent);
55              
56             # XXX No types
57 0           my $out = "([" . $self->type->dump(@_) . "] method " . $self->name;
58             # my $out = "(method " . $self->name;
59 0           my $args = join("", map { " " . $_->dump($indent, @_) } @{$self->args});
  0            
  0            
60 0 0         my $code = ! $self->code ? "(nocode)"
    0          
61             : ref($self->code) !~ /::/ ? ref($self->code)
62             : $self->code->dump($indent, @_)
63             ;
64              
65 0           $out = $out .
66             $sep . "(args" . $args . ")" .
67             $sep . $code . ")";
68              
69 0           return $out;
70             }
71              
72             # This should generate Perl code for the method
73             sub generate {
74 0     0 0   my $self = shift;
75 0           my $indent = shift;
76 0           $indent++;
77              
78 0 0         return "\n\n# No code in " . $self->name . "\n\n\n"
79             unless $self->code;
80              
81 0           my $proto = '$' . ('$' x @{$self->args});
  0            
82 0           my $rtproto = join("", map { ${ $_->type } } @{ $self->args });
  0            
  0            
  0            
83 0           my $head =
84             "# method " . $self->name . " proto o" . $rtproto . "\n" .
85             "sub _M_" . $self->name . " ($proto) {\n";
86             # XXX Generate warning if no return from nonvoid function.
87 0           my $tail = "\n\treturn undef;\n}\n";
88              
89 0           my @args = map { ', $_L_' . $_->name } @{ $self->args };
  0            
  0            
90 0           my $args = "\t" . 'my ($self' . join('', @args) . ') = @_;' .
91             "\n\t";
92              
93 0           return $head . $args . $self->code->generate($indent, @_) . $tail;
94             }
95              
96             # This has a weird prototype for a typecheck method.
97             sub typecheck_call {
98 0     0 0   my ($self, $program, $values, @rest) = @_;
99              
100 0 0         if ($self->flags & M_UNKNOWN) {
101 0           return $self->type;
102             }
103              
104             # print "Typecheck call: " . Dumper($values) . "\n";
105             # print "Typecheck call: " . Dumper($self) . "\n";
106              
107 0           my @values = @$values;
108 0           my $method = shift @values;
109              
110 0           my @args = @{ $self->args };
  0            
111              
112 0 0         if (@values < @args) {
    0          
113 0           $program->error("Too few arguments (" . scalar(@values) .
114             ") to function " . $method->name .
115             ", try " . scalar(@args));
116 0           return $self->type;
117             }
118             elsif (@values > @args) {
119 0           $program->error("Too many arguments (" . scalar(@values) .
120             ") to function " . $method->name .
121             ", try " . scalar(@args));
122 0           return $self->type;
123             }
124              
125 0           my $i = 1;
126 0           foreach my $decl (@args) {
127 0           my $val = $values->[$i];
128             # print "Matching arg " . $val->dump . " against " . $decl->dump . "\n";
129 0           my $arg = $val->promote($decl->type);
130 0 0         if (! $arg) {
    0          
131 0           $program->error("Argument $i to " . $self->name .
132             " is type " . $val->type->name .
133             " not type " . $decl->type->name);
134             }
135             elsif ($arg != $val) {
136 0           $arg->check($program, undef, @rest);
137 0           $values->[$i] = $arg;
138             }
139             # print "OK\n";
140             }
141             continue {
142 0           $i++;
143             }
144              
145             # print "Funcall " . $method->name . " checked and becomes type "
146             # . ${$method->type} . "\n" if 0;
147 0           return $self->type;
148             }
149              
150             sub generate_call {
151 0     0 0   my ($self, @args) = @_;
152 0           return '$self->_M_' . $self->name . "(" . join(", ", @args) .")";
153             }
154              
155             sub proto {
156 0     0 0   my ($self) = @_;
157 0           return $self->type->deparse . " " . $self->name . "(...)";
158             }
159              
160             1;