File Coverage

blib/lib/Anarres/Mud/Driver/Compiler/Type.pm
Criterion Covered Total %
statement 43 89 48.3
branch 4 42 9.5
condition n/a
subroutine 11 19 57.8
pod 0 13 0.0
total 58 163 35.5


line stmt bran cond sub pod time code
1             package Anarres::Mud::Driver::Compiler::Type;
2              
3 7     7   88887 use strict;
  7         16  
  7         265  
4 7     7   37 use warnings;
  7         12  
  7         217  
5 7         610 use vars qw($VERSION @ISA @EXPORT_OK %EXPORT_TAGS
6 7     7   32 %TYPENAMES %TYPECODES);
  7         33  
7 7     7   36 use Exporter;
  7         11  
  7         268  
8 7     7   43 use Carp;
  7         12  
  7         964  
9              
10             BEGIN {
11 7     7   522 $VERSION = 0.10;
12 7         148 @ISA = qw(DynaLoader Exporter);
13 7         23 @EXPORT_OK = qw(T_CLASS F_CONST F_LVALUE); # .xs adds more to this
14 7         21 %EXPORT_TAGS = (
15             all => \@EXPORT_OK,
16             );
17 7         47 require DynaLoader;
18 7         14033 bootstrap Anarres::Mud::Driver::Compiler::Type;
19             }
20              
21             %TYPENAMES = (
22             ${T_VOID()} => "void",
23             ${T_NIL()} => "nil",
24             ${T_UNKNOWN()} => "unknown",
25             ${T_BOOL()} => "boolean",
26             ${T_CLOSURE()} => "function",
27             ${T_INTEGER()} => "integer",
28             ${T_OBJECT()} => "object",
29             ${T_STRING()} => "string",
30             ${T_FAILED()} => "ERROR",
31             );
32              
33             %TYPECODES = (
34             ${T_VOID()} => "void",
35             ${T_NIL()} => "nil",
36             ${T_UNKNOWN()} => "mixed",
37             ${T_BOOL()} => "bool",
38             ${T_CLOSURE()} => "function",
39             ${T_INTEGER()} => "int",
40             ${T_OBJECT()} => "object",
41             ${T_STRING()} => "string",
42             ${T_FAILED()} => "ERROR",
43             );
44              
45             sub T_CLASS {
46 8     8 0 2257 my $class = __PACKAGE__;
47 8         14 my $name = shift;
48             # DEBUG
49 8 50       22 croak "Error: Class must be named." if ref($name);
50 16         44 my $self = T_M_CLASS_BEGIN . $name . T_M_CLASS_MID .
51 8         20 join('', map { $$_ } @_) . T_M_CLASS_END;
52 8         72 return $class->new($self);
53             }
54              
55             sub F_CONST () { 1 }
56             sub F_LVALUE () { 2 }
57              
58             sub array {
59 31     31 0 53 my ($self, $num) = @_;
60 31 50       78 $num = 1 unless defined $num;
61 31         64 my $out = "*" x $num . $$self;
62 31         323 return $self->new($out);
63             }
64              
65             sub mapping {
66 12     12 0 19 my ($self, $num) = @_;
67 12 50       35 $num = 1 unless defined $num;
68 12         22 my $out = "#" x $num . $$self;
69 12         60 return $self->new($out);
70             }
71              
72             sub dereference {
73 0     0 0 0 my ($self) = @_;
74 0         0 my $new;
75 0 0       0 if ($$self =~ /^[*#]/) {
  0 0       0  
76 0         0 $new = substr($$self, 1)
77             }
78             elsif ($$self eq ${ &T_STRING }) { # XXX Remove this case?
79 0         0 warn "Dereferencing string!";
80 0         0 $new = T_INTEGER;
81             }
82             else {
83 0         0 die "Cannot dereference nonreference type $$self";
84             }
85 0         0 return $self->new($new);
86             }
87              
88             sub is_array {
89 0     0 0 0 return ${$_[0]} =~ /^\*/;
  0         0  
90             }
91              
92             sub is_mapping {
93 0     0 0 0 return ${$_[0]} =~ /^#/;
  0         0  
94             }
95              
96             sub is_class {
97 0     0 0 0 return ${$_[0]} =~ /^{/;
  0         0  
98             }
99              
100             sub class {
101 0 0   0 0 0 return undef unless ${$_[0]} =~ /^{([^:]*):/;
  0         0  
102 0         0 return $1;
103             }
104              
105             sub dump {
106 6     6 0 598 return ${$_[0]};
  6         24  
107             }
108              
109             sub equals {
110             # Since we have unique types, the references should compare
111             # equal just as the referenced values do.
112 6         13 warn "Problem with type uniqueness"
113 6 50   6 0 13 if (($_[0] == $_[1]) != (${$_[0]} eq ${$_[1]}));
  6         19  
114 6         33 return ${$_[0]} eq ${$_[1]};
  6         10  
  6         35  
115             }
116              
117             # Called from Node->promote in Check.pm
118             sub promote {
119 0     0 0   my ($self, $node, $type) = @_;
120             # We might be promoted to a more specific type.
121             # We might be promoted to a less specific type.
122             # This routine must return a typechecked object.
123 0 0         if ($$self ne $$type) {
124             # print "Promoting " . sprintf("%-20.20s", $node->nodetype) .
125             # " from $$self to $$type\n";
126             }
127 0           return $node; # XXX do something here!
128             }
129              
130             sub name {
131 0     0 0   my ($self) = shift;
132 0           my $code = $$self;
133 0           my $out = "";
134 0           while (length $code) {
135 0 0         if ($code =~ s/^#//) {
    0          
    0          
    0          
    0          
    0          
136 0           $out .= "mapping of ";
137             }
138             elsif ($code =~ s/^\*//) {
139 0           $out .= "pointer to ";
140             }
141             elsif ($code =~ m/^z/) {
142 0           $out .= "constant ";
143             }
144             elsif ($code =~ m/^=/) {
145 0           $out .= "lvalue ";
146             }
147             elsif ($code =~ m/^{([^:]+):/) {
148 0           return $out . "class $1";
149             }
150             elsif ($TYPENAMES{$code}) {
151 0           return $out . $TYPENAMES{$code};
152             }
153             else {
154 0           die "Unknown type code $code!";
155             }
156             }
157 0           die "Invalid type code $$self !";
158             }
159              
160             # Currently only called from Method::proto
161             sub deparse {
162 0     0 0   my ($self) = shift;
163 0           my $code = $$self;
164 0           my $out = "";
165 0           while (length $code) {
166 0 0         if ($code =~ s/^#//) {
    0          
    0          
    0          
    0          
    0          
167 0           $out .= "#";
168             }
169             elsif ($code =~ s/^\*//) {
170 0           $out .= "*";
171             }
172             elsif ($code =~ m/^z/) {
173             # $out .= "const ";
174             }
175             elsif ($code =~ m/^=/) {
176             # $out .= "lvalue ";
177             }
178             elsif ($code =~ m/^{([^:]+):/) {
179 0           return "class $1 $out";
180             }
181             elsif ($TYPECODES{$code}) {
182 0 0         return "$TYPECODES{$code} $out" if length $out;
183 0           return $TYPECODES{$code};
184             }
185             else {
186 0           die "Unknown type code $code!";
187             }
188             }
189 0           die "Invalid type code $$self !";
190             }
191              
192             1;