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.065';
4              
5 101     101   35538 use strict;
  101         169  
  101         3731  
6 101     101   454 use warnings; no warnings 'utf8';
  101     101   157  
  101         2723  
  101         371  
  101         150  
  101         35804  
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 270032 my ($self,$var) = @_;
16 105413         92627 my $lvalue;
17              
18 105413         154776 for(reverse @$self) {
19 107729         97025 my $p = $_;
20 107729   100     236552 defined($p=$p->prototype) or next while !$p->exists($var);
21 104835         283262 return new JE::LValue $_, $var;
22             }
23             # if we get this far, then we create an lvalue without a base obj
24 578         1969 new JE::LValue \$self->[0], $var;
25             }
26              
27             sub new_var {
28 773     773 1 1146 my ($self,$var) = (shift,shift);
29 773         716 my $var_obj;
30 773         1934 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       1130 ref $_ eq 'JE::Object::Function::Call' and
35             $var_obj = $_,
36             last;
37             }
38 773 100       1749 defined $var_obj or $var_obj = $$self[0];
39              
40 773 100       1810 if (defined $var_obj->prop($var)) {
41 75 50       167 $var_obj->prop($var, shift) if @_;
42             }
43             else {
44 698 100       2194 $var_obj->prop($var, @_ ? shift :
45             $$self[0]->undefined);
46              
47             # This is very naughty code, but it works.
48 698 100       2782 $JE::Code::Expression::_eval or $var_obj->prop({
49             name => $var,
50             dontdel => 1,
51             });
52             }
53              
54 773 50       3335 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   8370 my($method) = $AUTOLOAD =~ /([^:]+)\z/;
60              
61             # deal with various ALLCAPS names
62 1337 50       3865 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         4658 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