File Coverage

blib/lib/JE/Scope.pm
Criterion Covered Total %
statement 29 34 85.2
branch 13 16 81.2
condition 2 2 100.0
subroutine 6 7 85.7
pod 2 2 100.0
total 52 61 85.2


line stmt bran cond sub pod time code
1             package JE::Scope;
2              
3             our $VERSION = '0.066';
4              
5 101     101   46868 use strict;
  101         193  
  101         4286  
6 101     101   505 use warnings; no warnings 'utf8';
  101     101   179  
  101         3432  
  101         450  
  101         179  
  101         40705  
7              
8             require JE::LValue;
9              
10             our $AUTOLOAD;
11              
12             # ~~~ We need a C method.
13              
14             sub find_var {
15 105413     105413 1 304727 my ($self,$var) = @_;
16 105413         110718 my $lvalue;
17              
18 105413         178688 for(reverse @$self) {
19 107729         108069 my $p = $_;
20 107729   100     279559 defined($p=$p->prototype) or next while !$p->exists($var);
21 104835         315434 return new JE::LValue $_, $var;
22             }
23             # if we get this far, then we create an lvalue without a base obj
24 578         2387 new JE::LValue \$self->[0], $var;
25             }
26              
27             sub new_var {
28 773     773 1 1454 my ($self,$var) = (shift,shift);
29 773         908 my $var_obj;
30 773         2400 for(reverse @$self[1..$#$self]) { # Object 0 can't be a call
31             # object. Omitting it should the-
32             # oretically make things margin-
33             # ally faster.
34 352 100       1227 ref $_ eq 'JE::Object::Function::Call' and
35             $var_obj = $_,
36             last;
37             }
38 773 100       2038 defined $var_obj or $var_obj = $$self[0];
39              
40 773 100       2101 if (defined $var_obj->prop($var)) {
41 75 50       202 $var_obj->prop($var, shift) if @_;
42             }
43             else {
44 698 100       2754 $var_obj->prop($var, @_ ? shift :
45             $$self[0]->undefined);
46              
47             # This is very naughty code, but it works.
48 698 100       3552 $JE::Code::Expression::_eval or $var_obj->prop({
49             name => $var,
50             dontdel => 1,
51             });
52             }
53              
54 773 50       4165 return new JE::LValue $var_obj, $var
55             unless not defined wantarray;
56             }
57              
58             sub AUTOLOAD { # This delegates the method to the global object
59 1337     1337   9838 my($method) = $AUTOLOAD =~ /([^:]+)\z/;
60              
61             # deal with various ALLCAPS names
62 1337 50       5203 if($method =~ /^[A-Z]+\z/) {
63 0         0 substr($method,0,0) = 'SUPER::';
64 0         0 local *@;
65 0         0 return eval { shift->$method(@_) };
  0         0  
66             }
67              
68 1337         5991 shift->[0]->$method(@_); # ~~~ Maybe I should use goto
69             # to remove AUTOLOAD from
70             # the call stack.
71             }
72              
73 0     0     sub DESTROY {}
74              
75             1;
76              
77             =head1 NAME
78              
79             JE::Scope - JavaScript scope chain (what makes closures work)
80              
81             =head1 DESCRIPTION
82              
83             JavaScript code runs within an execution context which has a scope chain
84             associated with it. This class implements this scope chain. When a variable
85             is accessed the objects in the scope chain are searched till the variable
86             is found.
87              
88             A JE::Scope object can also be used as global (JE) object. Any methods it
89             does not understand will be delegated to the object at the bottom of the
90             stack (the far end of the chain), so that C<< $scope->null >> means the
91             same thing as C<< $scope->[0]->null >>.
92              
93             Objects of this class consist of a reference to an array, the elements of
94             which are the objects in the chain (the first element
95             being the global object). (Think
96             of it as a stack.)
97              
98             =head1 METHODS
99              
100             =over 4
101              
102             =item find_var($name, $value)
103              
104             =item find_var($name)
105              
106             This method searches through
107             the scope chain, starting at the end of the array, until it
108             finds the
109             variable named by the first argument. If the second argument is
110             present, it sets the variable. It then returns an lvalue (a
111             JE::LValue object) that references the variable.
112              
113             =item new_var($name, $value)
114              
115             =item new_var($name)
116              
117             This method creates (and optionally sets the value of) a new
118             variable in the variable object (the same thing that JavaScript's C
119             keyword does) and returns an lvalue.
120              
121             The variable object is the first object in the scope chain
122             (searching from the top of the
123             stack) that is a call object, or C<< $scope->[0] >> if no call object is
124             found.
125              
126             =back
127              
128             =head1 CONSTRUCTOR
129              
130             None. Just bless an array reference. You should not need to do
131             this because it is done for you by the C and C
132             classes.
133              
134             =head1 SEE ALSO
135              
136             =over
137              
138             =item L
139              
140             =item L
141              
142             =item L
143              
144             =back
145              
146             =cut
147              
148              
149              
150