File Coverage

blib/lib/Dallycot/AST/Apply.pm
Criterion Covered Total %
statement 21 61 34.4
branch 0 14 0.0
condition 0 10 0.0
subroutine 7 14 50.0
pod 0 6 0.0
total 28 105 26.6


line stmt bran cond sub pod time code
1             package Dallycot::AST::Apply;
2             our $AUTHORITY = 'cpan:JSMITH';
3              
4             # ABSTRACT: Apply bindings to lambda
5              
6 23     23   12148 use strict;
  23         37  
  23         749  
7 23     23   103 use warnings;
  23         34  
  23         489  
8              
9 23     23   85 use utf8;
  23         33  
  23         100  
10 23     23   445 use parent 'Dallycot::AST';
  23         30  
  23         100  
11              
12 23     23   1346 use Carp qw(croak);
  23         36  
  23         1165  
13 23     23   104 use Promises qw(deferred);
  23         29  
  23         113  
14 23     23   4042 use Readonly;
  23         35  
  23         13551  
15              
16             Readonly my $EXPRESSION => 0;
17             Readonly my $BINDINGS => 1;
18             Readonly my $OPTIONS => 2;
19              
20             sub new {
21 0     0 0   my ( $class, $expression, $bindings, $options ) = @_;
22              
23 0   0       $class = ref $class || $class;
24 0   0       $bindings //= [];
25 0   0       $options //= {};
26 0           return bless [ $expression, $bindings, $options ] => $class;
27             }
28              
29             sub to_rdf {
30 0     0 0   my($self, $model) = @_;
31              
32             #
33             # node -> expression_set -> [ ... ]
34             #
35 0           return $model -> apply(
36             $self -> [0],
37             $self -> [1],
38             $self -> [2]
39             )
40             }
41              
42             sub simplify {
43 0     0 0   my ($self) = @_;
44              
45 0           return bless [
46             $self->[$EXPRESSION]->simplify,
47 0           [ map { $_->simplify } @{ $self->[$BINDINGS] } ],
  0            
48             $self->[$OPTIONS]
49             ] => __PACKAGE__;
50             }
51              
52             sub child_nodes {
53 0     0 0   my ($self) = @_;
54              
55 0 0         return $self->[$EXPRESSION], @{ $self->[$BINDINGS] || [] }, values %{ $self->[$OPTIONS] || {} };
  0 0          
  0            
56             }
57              
58             sub to_string {
59 0     0 0   my ($self) = @_;
60              
61             return
62 0           "("
63             . $self->[$EXPRESSION]->to_string . ")("
64             . join(
65             ", ",
66 0           ( map { $_->to_string } @{ $self->[$BINDINGS] } ),
  0            
67 0           ( map { $_ . " -> " . $self->[$OPTIONS]->{$_}->to_string }
68 0           sort keys %{ $self->[$OPTIONS] }
69             )
70             ) . ")";
71             }
72              
73             sub execute {
74 0     0 0   my ( $self, $engine ) = @_;
75              
76 0           my $expr = $self->[$EXPRESSION];
77 0 0         if ( $expr->isa('Dallycot::Value') ) {
78 0           $expr = bless [$expr] => 'Dallycot::AST::Identity';
79             }
80              
81             return $engine->execute($expr)->then(
82             sub {
83 0     0     my ($lambda) = @_;
84 0 0         if ( !$lambda ) {
    0          
85 0           croak "Undefined value can not be a function.";
86             }
87             elsif ( $lambda->can('apply') ) {
88 0           my @bindings = @{ $self->[$BINDINGS] };
  0            
89 0 0 0       if ( @bindings && $bindings[-1]->isa('Dallycot::AST::FullPlaceholder') ) {
90 0 0         if ( $lambda->min_arity < @bindings ) {
91              
92             # we have something like f(..., ___) indicating we *want* a lambda
93             # since we don't have room for any placeholders, we'll just create
94             # a lambda and return it
95             # we need to evaluate any options or bindings first
96 0           pop @bindings;
97 0           return Dallycot::AST::Lambda->new(
98             Dallycot::AST::Apply->new( $self->[$EXPRESSION], \@bindings, $self->[$OPTIONS] ) )
99             ->execute($engine);
100             }
101             else {
102 0           pop @bindings;
103 0           push @bindings,
104             ( bless [] => 'Dallycot::AST::Placeholder' ) x ( $lambda->min_arity - @bindings );
105             }
106             }
107 0           return $lambda->apply( $engine, { %{ $self->[$OPTIONS] } }, @bindings );
  0            
108             }
109             else {
110 0           croak "Value of type " . $lambda->type . " can not be used as a function.";
111             }
112             }
113 0           );
114             }
115              
116             1;