root/misc/JavaScript-FrontEnd/ARuntime.pm

Revision 6852, 8.7 kB (checked in by bsmith, 3 years ago)

* changed ??:: to ??!! in docs, ext and modules.

  • Property svn:mime-type set to text/plain; charset=UTF-8
  • Property svn:eol-style set to native
Line 
1=pod
2
3This file is the beginning of a simple JavaScript-on-p6 runtime.
4It seems likely there will be more than one.
5
6Design goals:
7 1 Correctness - mirror the spec.
8 2 Interoperation - allow blending of p6 and js objects.
9   (Even though this impairs 1?)
10Please note efficiency isnt currently on the goal list.
11
12CAVEAT - This file so far represents only a an hour or two of work.
13It is very much in a state of flux.
14
15=cut
16
17class JSX::PseudoValue;
18class JSX::InternalValue is JSX::PseudoValue;
19class JSX::InternalValue::Reference  is JSX::InternalValue;
20class JSX::InternalValue::List       is JSX::InternalValue;
21class JSX::InternalValue::Completion is JSX::InternalValue;
22class JSX::Value is JSX::PseudoValue;
23class JSX::ValuePrimitive is JSX::Value;
24class JSX::Value::Undefined is JSX::ValuePrimitive;
25class JSX::Value::Null      is JSX::ValuePrimitive;
26class JSX::Value::Boolean   is JSX::ValuePrimitive;
27class JSX::Value::Number    is JSX::ValuePrimitive;
28class JSX::Value::String    is JSX::ValuePrimitive;
29class JSX::Value::Object is JSX::Value;
30class JSX::Value::Array is JSX::Value::Object;
31
32class JSX::PropertyAttributes {
33    has $.ReadOnly;
34    has $.DontEnum;
35    has $.DontDelete;
36}
37
38class JSX::Value;
39has $.property_value;
40has $.property_attributes;
41# 8.6.2.1
42method <[[Get]]> ($O: JSX::String $P) {
43    my $Result2 = $O.property_value{$P};
44    return $Result2 if defined $Result2;
45    my $proto = $O.<[[Prototype]]>;
46    return JSX::undefined if $proto ~~ JSX::null;
47    return $proto.<[[Get]]>($P);
48}
49# 8.6.2.2
50method <[[Put]]> ($O: JSX::String $P, JSX::Value $V) {
51    my $Result1 = $O.<[[CanPut]]>($P);
52    return if $Result1 ~~ JSX::false;
53    if $O.property_value.exists($P) {
54        $O.property_value($P) = $V;
55        return;
56    }
57    $O.property_value($P) = $V;
58    return;
59}   
60# 8.6.2.3
61method <[[CanPut]]> ($O: JSX::String $P) {
62    if $O.property_value.exists($P) {
63        my $attr = $O.property_attributes{$P};
64        return JSX::false if $attr && $attr.ReadOnly;
65        return JSX::true;
66    }
67    my $proto = $O.<[[Prototype]]>;
68    return JSX::true if $proto ~~ JSX::null;
69    return $proto.<[[CanPut]]>($P);
70}
71# 8.6.2.4
72method <[[HasProperty]]> ($O: JSX::String $P) {
73    return JSX::true if $O.property_value.exists($P);
74    my $proto = $O.<[[Prototype]]>;
75    return JSX::false if $proto ~~ JSX::null;
76    return $proto.<[[CanPut]]>($P);
77}
78# 8.6.2.5
79method <[[Delete]]> ($O: JSX::String $P) {
80    return JSX::true if !$O.property_value.exists($P);
81    my $attr = $O.property_attributes{$P};
82    return JSX::false if $attr && $attr.ReadOnly;
83    delete $O.property_value{$P};
84    delete $O.property_attribute{$P};
85    return JSX::true;
86}
87# 8.6.2.6
88multi method <[[DefaultValue]]> ($O: ?$hint = 'Number') {
89    if $hint eq 'String' {
90        my $Result1 = $O.<[[Get]]>('toString');
91        if $Result1.isa(JSX::Value::Object) {
92            my $Result3 = JSX::with_this($O) { $Result1.<[[Get]]>() };
93            return $Result3 if $Result3.isa(JSX::ValuePrimitive);
94        } # 5
95        my $Result5 = $O.<[[Get]]>('valueOf');
96        if $Result5.isa(JSX::Value::Object) {
97            my $Result7 = JSX::with_this($O) { $Result1.<[[Get]]>() };
98            return $Result7 if $Result7.isa(JSX::ValuePrimitive);
99        } # 9
100        raise TypeError;
101    } elsif $hint eq 'Number' {
102        my $Result1 = $O.<[[Get]]>('valueOf');
103        if $Result1.isa(JSX::Value::Object) {
104            my $Result3 = JSX::with_this($O) { $Result1.<[[Get]]>() };
105            return $Result3 if $Result3.isa(JSX::ValuePrimitive);
106        } # 5
107        my $Result5 = $O.<[[Get]]>('toString');
108        if $Result5.isa(JSX::Value::Object) {
109            my $Result7 = JSX::with_this($O) { $Result1.<[[Get]]>() };
110            return $Result7 if $Result7.isa(JSX::ValuePrimitive);
111        } # 9
112        raise TypeError;
113    } else {
114        die "bug - invalid hint $hint";
115    }
116}
117
118# 8.7 The Reference Type
119class JSX::InternalValue::Reference {
120    has $.base_object;
121    has $.property_name;
122    method GetBase ($O:) { $.base_object }
123    method GetPropertyName ($O:) { $.property_name }
124}
125# 8.7.1
126method GetValue (JSX::PsuedoValue $V) { $V }
127method GetValue (JSX::InternalValue::Reference $V) {
128    my $Result2 = GetBase($V);
129    raise ReferenceError if $Result2 ~~ JSX::null;
130    my $Result4 = $Result2.<[[Get]]>(GetPropertyName($V));
131    return $Result4;
132}
133# 8.7.2
134method PutValue (JSX::PsuedoValue $V) { raise ReferenceError; }
135method PutValue (JSX::InternalValue::Reference $V, $W) {
136    my $Result2 = GetBase($V);
137    if !($Result2 ~~ JSX::null) {
138        $Result2.<[[Put]]>(GetPropertyName($V),$W);
139        return;
140    } # 6
141    JSX::global_object.<[[Put]]>(GetPropertyName($V),$W);
142    return;
143}
144
145# 8.8 The List Type
146class JSX::InternalValue::List is Array;
147
148# 8.9 The Completion Type
149class JSX::InternalValue::Completion_type { # XXX - should be enum
150   has $.normal;
151   has $.break;
152   has $.continue;
153   has $.return;
154   has $.throw;
155}
156class JSX::InternalValue::Completion {
157   submethod BUILD { $.type = JSX::InternalValue::Completion_type.new(); }
158   has $.type;
159   has $.value;
160   has $.target;
161   method is_abrupt_completion() { !$.type.normal }
162}
163# empty is represented by undef.
164
165# 9. Type Conversion
166
167# 9.1
168multi sub ToPrimitive(JSX::Value::Object $o) {$o.<[[DefaultValue]]>}
169multi sub ToPrimitive(JSX::Value $v) {$v}
170
171# 9.2
172multi sub ToBoolean(JSX::Value::Undefined $v) { JSX::false }
173multi sub ToBoolean(JSX::Value::Null $v)      { JSX::false }
174multi sub ToBoolean(JSX::Value::Boolean $v)   { $v }
175multi sub ToBoolean(JSX::Value::Number $v) {
176    +$v == (+0|-0|NaN) ?? JSX::false !! JSX::true;
177}
178multi sub ToBoolean(JSX::Value::String $v) {
179    ~$v eq "" ?? JSX::false !! JSX::true;
180}
181multi sub ToBoolean(JSX::Value::Object $v) { JSX::true }
182
183# 9.3
184multi sub ToNumber(JSX::Value::Undefined $v) { NaN }
185multi sub ToNumber(JSX::Value::Null $v)      { +0 }
186multi sub ToNumber(JSX::Value::Boolean $v)   { ?$v :: JSX::true :: +0 }
187multi sub ToNumber(JSX::Value::Number $v)    { $v }
188multi sub ToNumber(JSX::Value::String $v) {
189    my $s = ~$v;
190    return NaN if $s !~ rx/^<TheGrammar.StringNumericLiteral>$/;
191    $s ~~ s:g/<TheGrammar.StrWhiteSpaceChar>+//;
192    $s ~~ s/^([\+|\-]?)0+(<[0..9]>)/$1$2/;
193    return +0 if $s eq "";
194    return +$s;
195}
196multi sub ToNumber(JSX::Value::Object $v) {
197    my $Result1 = ToPrimitive($v,'Number');
198    my $Result2 = ToNumber($Result1);
199    return $Result2;
200}
201
202# 9.4
203multi sub ToInteger(JSX::Value $v) {
204    use Math qw(sign floor abs);
205    my $Result1 = ToNumber($v);
206    return +0 if $Result1 == NaN;
207    return $Result1 if $Result1 == (+0|-0|Inf|-Inf);
208    my $Result4 = sign($Result1) * floor(abs($Result1));
209    return $Result4;
210}
211
212# 9.5
213multi sub ToInt32(JSX::Value $v) {
214    use Math qw(sign floor abs);
215    my $Result1 = ToNumber($v);
216    return +0 if $Result1 == (NaN|+0|-0|Inf|-Inf);
217    my $Result3 = sign($Result1) * floor(abs($Result1));
218    my $n2_32 = 2**32;
219    my $n2_31 = 2**31;
220    my $Result4 = $Result3 % $n2_32;
221    return $Result4-$n2_32 if $Result4 >= $n2_31;
222    return $Result4;
223}
224
225# 9.6
226multi sub ToUint32(JSX::Value $v) {
227    use Math qw(sign floor abs);
228    my $Result1 = ToNumber($v);
229    return +0 if $Result1 == (NaN|+0|-0|Inf|-Inf);
230    my $Result3 = sign($Result1) * floor(abs($Result1));
231    my $n2_32 = 2**32;
232    my $Result4 = $Result3 % $n2_32;
233    return $Result4;
234}
235
236# 9.7
237multi sub ToUint16(JSX::Value $v) {
238    use Math qw(sign floor abs);
239    my $Result1 = ToNumber($v);
240    return +0 if $Result1 == (NaN|+0|-0|Inf|-Inf);
241    my $Result3 = sign($Result1) * floor(abs($Result1));
242    my $n2_16 = 2**16;
243    my $Result4 = $Result3 % $n2_16;
244    return $Result4;
245}
246
247# 9.8
248
249# 9.9
250
251
252
253
254
255class JSX::Value::Array;
256submethod BUILD {
257    $.property_attributes{'length'} =
258        JSX::PropertyAttributes.new(:DontEnum :DontDelete);
259}
260# 15.4.5.1
261method <[[Put]]> ($A: JSX::String $P, JSX::Value $V) {
262    my $Result1 = $A.<[[CanPut]]>($P);
263    return if $Result1 ~~ JSX::false;
264    if $A.property_value.exists($P) {
265        if $P eq 'length' { # 12-16
266            my $Result12 = ToUint32($V);
267            raise RangeError if $Result12 != ToNumber($V);
268            my $length = +($A.property_value{'length'});
269            my $k;
270            loop(;$k < $length; $k++) {
271                my $key = $k; # Eh. Spec would have us use ToString(k).
272                $A.<[[Delete]]>($k) if exists $A.property_value{$key};
273                # XXX - need to wrap $k?
274            }
275            $A.property_value{$P} = $Result12;
276            return;
277        }
278        # 5
279        $A.property_value($P) = $V;
280    } else { # 7
281        $A.property_value($P) = $V;
282    }
283    # 8
284    my sub not_an_array_index($P){ !($P ~~ rx:perl5/\A\d+\Z/); };
285    return if not_an_array_index($P);
286    my $uint = ToUint32($P);
287    return if $uint < $A.property_value{'length'};
288    $A.property_value{'length'} = $uint + 1; #XXX dont forget + wrappers
289    return;
290}   
Note: See TracBrowser for help on using the browser.