File Coverage

blib/lib/Data/Typed/Expression/Env.pm
Criterion Covered Total %
statement 42 58 72.4
branch 23 42 54.7
condition 1 3 33.3
subroutine 6 10 60.0
pod 5 5 100.0
total 77 118 65.2


line stmt bran cond sub pod time code
1             package Data::Typed::Expression::Env;
2              
3 2     2   1659 use Carp 'croak';
  2         3  
  2         80  
4              
5 2     2   10 use warnings;
  2         3  
  2         42  
6 2     2   9 use strict;
  2         3  
  2         1432  
7              
8             =head1 NAME
9              
10             Data::Typed::Expression::Env - Evalutation environment for typed expressions
11              
12             =head1 VERSION
13              
14             Version 0.005
15              
16             =cut
17              
18             our $VERSION = '0.005';
19              
20             =head1 SYNOPSIS
21              
22             See L.
23              
24             =head1 DESCRIPTION
25              
26             An environment is an object describing known types and variables to be used by
27             expressions of type L. Types can be marked as simple
28             ones or defined as compounds (structures) with fields of other types.
29              
30             =head1 METHODS
31              
32             =head2 new
33              
34             Creates a new enviroment in which expressions can be evaluated.
35              
36             Arguments are two hashrefs, the first one containing types declarations, the
37             second one containing variables definitions.
38              
39             Each type declaration is a single hash entry, with type name being the key and
40             type definition being the value.
41              
42             Type definition is either C, when there is nothing "internal" about the
43             type or a hashref, for compound types. Each entry in compound type definition
44             is a mapping from a compound element name to its type name.
45              
46             For example, if we define the C type as having "color" property, which is
47             represented as RGB triple, "price" as double and "name" as a string, the
48             corresponding type definitions can look like:
49              
50             {
51             car => {
52             color => 'color',
53             price => 'double',
54             name => 'string'
55             },
56             color => {
57             r => 'double',
58             g => 'double',
59             b => 'double'
60             },
61             double => undef,
62             string => undef
63             }
64              
65             Variables definition is a mapping from variable name to its type name.
66              
67             =cut
68              
69             sub new {
70 1     1 1 98 my ($class, $types, $vars) = @_;
71 1 50       5 $vars = { } unless defined $vars;
72 1 50       4 $types = { } unless defined $types;
73 1         4 my $self = {
74             t => $types,
75             v => $vars
76             };
77            
78 1         5 return bless $self, $class;
79             }
80              
81             =head2 new_with
82              
83             Creates a new environment based on the current one.
84              
85             The created environment contains all the types and variables from the current
86             environment, as well as the new types and variables passed as the arguments,
87             in the same way as to L method.
88              
89             If types or variables which are defined in the current object and also passed
90             as parameters, definitions given in parameters override the current ones in the
91             created object.
92              
93             =cut
94              
95             sub new_with {
96 0     0 1 0 my ($self, $types, $vars) = @_;
97 0         0 my $t = {
98 0         0 %{$self->{t}},
99             %$types
100             };
101 0         0 my $v = {
102 0         0 %{$self->{v}},
103             %$vars
104             };
105 0         0 return (ref $self)->new($t, $v);
106             }
107              
108             =head2 get_type_def
109              
110             Returns type definition for a given type name, as passed to L.
111              
112             =cut
113              
114             sub get_type_def {
115 0     0 1 0 return $_[0]->{t}{$_[1]};
116             }
117              
118             =head2 get_var_type
119              
120             Returns variable type name, as passed to L.
121              
122             =cut
123              
124             sub get_var_type {
125 0     0 1 0 return $_[0]->{v}{$_[1]};
126             }
127              
128             =head2 validate
129              
130             Checks if the given expression represents a valid one, in the context of the
131             current environent.
132              
133             For expression to be valid, all used variables, types and components must exist
134             in the environment, and appropriate operators arguments must be of special and
135             coherent types (e.g. C for array indexing or C or C for
136             mathematical operations).
137              
138             Returns name of the type of passed expression.
139              
140             =cut
141              
142             sub validate {
143 9     9 1 7112 return $_[0]->_validate_ast($_[1]->{ast});
144             }
145              
146             sub _check_const_type {
147 0 0   0   0 if ($_[0] =~ /^\d+(\.\d+)?$/) {
148 0 0       0 return (defined $2) ? 'double' : 'int';
149             }
150            
151 0         0 undef;
152             }
153              
154             sub _validate_ast {
155 50     50   77 my ($self, $ast) = @_;
156 50 50       109 return '' unless defined $ast;
157            
158 50 50       162 my ($op, $arg) = (ref $ast) ?
159             ($ast->{op}, $ast->{arg}) :
160             ('V', $ast);
161              
162 50 100       228 if ($op eq 'I') {
    50          
    100          
    100          
    100          
    50          
163 9         21 return 'int';
164             } elsif ($op eq 'D') {
165 0         0 return 'double';
166             } elsif ($op eq 'V') {
167 14 50       42 if (ref $arg) {
168 0         0 $arg = $arg->[0];
169             }
170 14 100       74 croak "Undefined var: $arg" unless exists $self->{v}{$arg};
171 13         44 return $self->{v}{$arg};
172             } elsif ($op eq '.') {
173 13 50 33     129 if (ref $arg->[1] && $arg->[1]{op} ne 'V') {
174 0         0 croak "Unexpected element type ($arg->[1]{op}) on right side of '.'";
175             }
176 13         80 my $subt = $self->_validate_ast($arg->[0]);
177 11         26 my $e = $arg->[1]{arg};
178 11 50       41 croak "Tried to get elements of simple type ($subt)"
179             unless ref $self->{t}{$subt};
180 11 50       38 croak "Type ($subt) has no element named $e"
181             unless exists $self->{t}{$subt}{$e};
182 11         41 return $self->{t}{$subt}{$e};
183             } elsif ($op =~ m{[-+*/]}) {
184 6         10 my $t = 'int';
185 6         12 for (@$arg) {
186 12         52 my $tt = $self->_validate_ast($_);
187 12 50       36 if ($tt eq 'int') {
    0          
188             # fine
189             } elsif ($tt eq 'double') {
190 0         0 $t = 'double';
191             } else {
192 0         0 croak "Arithmetic operation ($op) on non-numeric type ($t)";
193             }
194             }
195 6         12 return $t;
196             } elsif ($op eq '[]') {
197 8         26 my ($arr, @ind) = @$arg;
198 8         47 my $subt = $self->_validate_ast($arr);
199 8         20 for (@ind) {
200 8         17 my $indt = $self->_validate_ast($_);
201 8 50       171 croak "Can't index ($subt) with non-int ($indt) type"
202             if $indt ne 'int';
203             }
204 8         30 my $indbr = '[]' x int(@ind);
205 8 50       92 $subt =~ s/\Q$indbr\E$// or
206             croak "Tried to index non-array type ($subt) with ($indbr)";
207 8         43 return $subt;
208             }
209             }
210              
211             1;
212