develooper Front page | perl.cvs.parrot | Postings from December 2008

[svn:parrot] r34320 - in trunk/languages/ecmascript: . config/makefiles src/builtin src/classes src/parser t

From:
tewk
Date:
December 24, 2008 00:09
Subject:
[svn:parrot] r34320 - in trunk/languages/ecmascript: . config/makefiles src/builtin src/classes src/parser t
Message ID:
20081224080925.D0FFBCBA12@x12.develooper.com
Author: tewk
Date: Wed Dec 24 00:09:24 2008
New Revision: 34320

Added:
   trunk/languages/ecmascript/src/classes/
   trunk/languages/ecmascript/src/classes/Boolean.pir
   trunk/languages/ecmascript/src/classes/Completion.pir
   trunk/languages/ecmascript/src/classes/List.pir
   trunk/languages/ecmascript/src/classes/Null.pir
   trunk/languages/ecmascript/src/classes/Number.pir
   trunk/languages/ecmascript/src/classes/Object.pir
   trunk/languages/ecmascript/src/classes/Reference.pir
   trunk/languages/ecmascript/src/classes/String.pir
   trunk/languages/ecmascript/src/classes/Undefined.pir
   trunk/languages/ecmascript/t/02-sanity-var.t
   trunk/languages/ecmascript/t/03-boolean.t
Modified:
   trunk/languages/ecmascript/config/makefiles/root.in
   trunk/languages/ecmascript/js.pir
   trunk/languages/ecmascript/src/builtin/builtins.pir
   trunk/languages/ecmascript/src/parser/actions.pm
   trunk/languages/ecmascript/src/parser/grammar.pg

Log:
[js] the beginning of core types


Modified: trunk/languages/ecmascript/config/makefiles/root.in
==============================================================================
--- trunk/languages/ecmascript/config/makefiles/root.in	(original)
+++ trunk/languages/ecmascript/config/makefiles/root.in	Wed Dec 24 00:09:24 2008
@@ -41,6 +41,12 @@
   src/gen_grammar.pir \
   src/gen_actions.pir \
   src/builtin/builtins.pir \
+  src/classes/Object.pir \
+  src/classes/Null.pir \
+  src/classes/Boolean.pir \
+  src/classes/Number.pir \
+  src/classes/String.pir \
+  src/classes/Undefined.pir \
 
 #PMCS = \
 #  jsobject \

Modified: trunk/languages/ecmascript/js.pir
==============================================================================
--- trunk/languages/ecmascript/js.pir	(original)
+++ trunk/languages/ecmascript/js.pir	Wed Dec 24 00:09:24 2008
@@ -80,6 +80,12 @@
 .namespace []
 
 .include 'src/builtin/builtins.pir'
+.include 'src/classes/Object.pir'
+.include 'src/classes/Boolean.pir'
+.include 'src/classes/Null.pir'
+#.include 'src/classes/Number.pir'
+#.include 'src/classes/String.pir'
+#.include 'src/classes/Undefined.pir'
 
 
 # Local Variables:

Modified: trunk/languages/ecmascript/src/builtin/builtins.pir
==============================================================================
--- trunk/languages/ecmascript/src/builtin/builtins.pir	(original)
+++ trunk/languages/ecmascript/src/builtin/builtins.pir	Wed Dec 24 00:09:24 2008
@@ -15,8 +15,28 @@
     print $P1
     goto print_loop
   end_print_loop:
+    print "\n"
 .end
 
+.sub 'version'
+    .param pmc version :optional
+    .param int has_version :opt_flag
+
+    $P1 = get_global '+$VERSION'
+    if_null $P1, unnullit
+    unless has_version goto ret
+    set_global '+$VERSION', version
+  ret:
+    .return ($P1)
+  unnullit:
+#    $P1 = new 'Integer'
+    $P1 = box 0
+    set_global '+$VERSION', $P1
+    .return ($P1)
+.end
+
+
+
 ## constructor for a object literals. It takes advantages of
 ## the Parrot Calling Conventions using :slurpy and :named flags,
 ## meaning that the parameter C<fields> is a hash, which is kinda
@@ -313,6 +333,14 @@
 
 .sub 'prefix:typeof'
     .param pmc op
+    $S0 = typeof op
+
+    $S1 = 'unknown'
+    ne $S0, 'Sub', n1
+    $S1 = 'function'
+    n1:
+
+    .return ($S1)
 .end
 
 .sub 'prefix:+'

Added: trunk/languages/ecmascript/src/classes/Boolean.pir
==============================================================================
--- (empty file)
+++ trunk/languages/ecmascript/src/classes/Boolean.pir	Wed Dec 24 00:09:24 2008
@@ -0,0 +1,69 @@
+## $Id: Bool.pir 32793 2008-11-18 03:21:53Z particle $
+
+=head1 TITLE
+
+Bool - Javascript Boolean Type and values
+
+=head1 DESCRIPTION
+
+This file sets up the Javascript C<Boolean> type, and initializes
+symbols for C<Boolean::True> and C<Boolean::False>.
+
+=head1 Methods
+
+=over 4
+
+=cut
+
+.namespace ['JSBoolean']
+
+.sub 'onload' :anon :init :load
+    .local pmc jsmeta, boolproto
+    jsmeta = get_hll_global ['JSObject'], '$!JSMETA'
+    boolproto = jsmeta.'new_class'('JSBoolean', 'parent'=>'Boolean')
+    #boolproto = jsmeta.'new_class'('Boolean')
+    #boolproto.'!IMMUTABLE'()
+    jsmeta.'register'('Boolean', 'parent'=>boolproto, 'protoobject'=>boolproto)
+
+    $P0 = boolproto.'new'()
+    $P0 = 0
+    set_hll_global ['JSBoolean'], 'false', $P0
+
+    $P0 = boolproto.'new'()
+    $P0 = 1
+    set_hll_global ['JSBoolean'], 'true', $P0
+.end
+
+.sub 'get_string' :vtable
+  .param pmc self
+   $I0 = self
+   unless self goto f
+  .return ("true")
+  f:
+  .return ("false")
+.end
+
+.sub 'ACCEPTS' :method
+    .param pmc topic
+    .return (self)
+.end
+
+
+.sub 'js' :method
+    if self goto false
+    .return ('false')
+  false:
+    .return ('true')
+.end
+
+
+=back
+
+=cut
+
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:

Added: trunk/languages/ecmascript/src/classes/Completion.pir
==============================================================================
--- (empty file)
+++ trunk/languages/ecmascript/src/classes/Completion.pir	Wed Dec 24 00:09:24 2008
@@ -0,0 +1,90 @@
+## $Id: Completion.pir 33898 2008-12-14 19:56:12Z pmichaud $
+
+=head1 NAME
+
+src/classes/Completion.pir - Completion objects
+
+=head1 DESCRIPTION
+
+=cut
+
+.namespace []
+
+.sub '' :anon :load :init
+    .local pmc jsmeta, nilproto
+    jsmeta = get_hll_global ['JSObject'], '$!JSMETA'
+    nilproto = jsmeta.'new_class'('Completion', 'parent'=>'Failure')
+    $P0 = nilproto.'new'()
+    set_hll_global ['Undefined'], 'undef', $P0
+    .end
+.end
+
+=head2 Methods
+
+=over
+
+=item 'list'
+
+=cut
+
+.namespace ['Completion']
+.sub 'list' :method
+    $P0 = new 'List'
+    .return ($P0)
+.end
+
+
+=item 'shift'
+
+=cut
+
+.namespace ['Completion']
+.sub 'shift' :method :vtable('shift_pmc')
+    .return (self)
+.end
+
+=back
+
+=head2 Coercion methods
+
+=over
+
+=item Scalar
+
+=cut
+
+.namespace ['Completion']
+.sub 'Scalar' :method
+    $P0 = new 'Failure'
+    .return ($P0)
+.end
+
+
+=back
+
+=head2 Private methods
+
+=over
+
+=item !flatten
+
+Return an empty list when flattened.
+
+=cut
+
+.namespace ['Completion']
+.sub '!flatten' :method
+    .tailcall self.'list'()
+.end
+
+
+=back
+
+=cut
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
+

Added: trunk/languages/ecmascript/src/classes/List.pir
==============================================================================
--- (empty file)
+++ trunk/languages/ecmascript/src/classes/List.pir	Wed Dec 24 00:09:24 2008
@@ -0,0 +1,90 @@
+## $Id: Nil.pir 33898 2008-12-14 19:56:12Z pmichaud $
+
+=head1 NAME
+
+src/classes/List.pir - List objects
+
+=head1 DESCRIPTION
+
+=cut
+
+.namespace []
+
+.sub '' :anon :load :init
+    .local pmc jsmeta, nilproto
+    jsmeta = get_hll_global ['JSObject'], '$!JSMETA'
+    nilproto = jsmeta.'new_class'('List', 'parent'=>'Failure')
+    $P0 = nilproto.'new'()
+    set_hll_global ['List'], 'undef', $P0
+    .end
+.end
+
+=head2 Methods
+
+=over
+
+=item 'list'
+
+=cut
+
+.namespace ['Nil']
+.sub 'list' :method
+    $P0 = new 'List'
+    .return ($P0)
+.end
+
+
+=item 'shift'
+
+=cut
+
+.namespace ['Nil']
+.sub 'shift' :method :vtable('shift_pmc')
+    .return (self)
+.end
+
+=back
+
+=head2 Coercion methods
+
+=over
+
+=item Scalar
+
+=cut
+
+.namespace ['Nil']
+.sub 'Scalar' :method
+    $P0 = new 'Failure'
+    .return ($P0)
+.end
+
+
+=back
+
+=head2 Private methods
+
+=over
+
+=item !flatten
+
+Return an empty list when flattened.
+
+=cut
+
+.namespace ['Nil']
+.sub '!flatten' :method
+    .tailcall self.'list'()
+.end
+
+
+=back
+
+=cut
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
+

Added: trunk/languages/ecmascript/src/classes/Null.pir
==============================================================================
--- (empty file)
+++ trunk/languages/ecmascript/src/classes/Null.pir	Wed Dec 24 00:09:24 2008
@@ -0,0 +1,91 @@
+## $Id: Nil.pir 33898 2008-12-14 19:56:12Z pmichaud $
+
+=head1 NAME
+
+src/classes/Nil.pir - Nil objects
+
+=head1 DESCRIPTION
+
+=cut
+
+.namespace []
+
+.sub '' :anon :load :init
+    .local pmc jsmeta, nilproto
+    jsmeta = get_hll_global ['JSObject'], '$!JSMETA'
+    nilproto = jsmeta.'new_class'('JSNull', 'parent'=>'Null')
+    jsmeta.'register'('Null', 'parent'=>nilproto, 'protoobject'=>nilproto)
+
+    $P0 = nilproto.'new'()
+    set_hll_global ['Null'], 'null', $P0
+    .end
+
+=head2 Methods
+
+=over
+
+=item 'list'
+
+=cut
+
+.namespace ['Nil']
+.sub 'list' :method
+    $P0 = new 'List'
+    .return ($P0)
+.end
+
+
+=item 'shift'
+
+=cut
+
+.namespace ['Nil']
+.sub 'shift' :method :vtable('shift_pmc')
+    .return (self)
+.end
+
+=back
+
+=head2 Coercion methods
+
+=over
+
+=item Scalar
+
+=cut
+
+.namespace ['Nil']
+.sub 'Scalar' :method
+    $P0 = new 'Failure'
+    .return ($P0)
+.end
+
+
+=back
+
+=head2 Private methods
+
+=over
+
+=item !flatten
+
+Return an empty list when flattened.
+
+=cut
+
+.namespace ['Nil']
+.sub '!flatten' :method
+    .tailcall self.'list'()
+.end
+
+
+=back
+
+=cut
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
+

Added: trunk/languages/ecmascript/src/classes/Number.pir
==============================================================================
--- (empty file)
+++ trunk/languages/ecmascript/src/classes/Number.pir	Wed Dec 24 00:09:24 2008
@@ -0,0 +1,104 @@
+## $Id: Num.pir 32597 2008-11-13 08:04:20Z pmichaud $
+
+=head1 TITLE
+
+Num - JS numbers
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item onload()
+
+=cut
+
+.namespace [ 'Num' ]
+
+.sub 'onload' :anon :init :load
+    .local pmc jsmeta, numproto
+    jsmeta = get_hll_global ['JSObject'], '$!JSMETA'
+    numproto = jsmeta.'new_class'('Num', 'parent'=>'Float Any')
+    numproto.'!IMMUTABLE'()
+    jsmeta.'register'('Float', 'parent'=>numproto, 'protoobject'=>numproto)
+
+    # Override the proto's ACCEPT method so we also accept Ints.
+    .const 'Sub' $P0 = "Num::ACCEPTS"
+    $P1 = typeof numproto
+    $P1.'add_method'('ACCEPTS', $P0)
+.end
+
+
+.sub 'Num::ACCEPTS' :anon :method
+    .param pmc topic
+
+    ##  first, try our superclass .ACCEPTS
+    $P0 = get_hll_global 'Any'
+    $P1 = find_method $P0, 'ACCEPTS'
+    $I0 = self.$P1(topic)
+    unless $I0 goto try_int
+    .return ($I0)
+
+  try_int:
+    $P0 = get_hll_global 'Int'
+    $I0 = $P0.'ACCEPTS'(topic)
+    .return ($I0)
+.end
+
+
+=item ACCEPTS()
+
+=cut
+
+.sub 'ACCEPTS' :method
+    .param num topic
+    .tailcall 'infix:=='(topic, self)
+.end
+
+
+=item js()
+
+Returns a JS representation of the Num.
+
+=cut
+
+.sub 'js' :method
+    $S0 = self
+    .return($S0)
+.end
+
+
+=item WHICH()
+
+Returns the identify value.
+
+=cut
+
+.sub 'WHICH' :method
+    $N0 = self
+    .return ($N0)
+.end
+
+
+=item infix:===
+
+Overridden for Num.
+
+=cut
+
+.namespace []
+.sub 'infix:===' :multi(Float,Float)
+    .param num a
+    .param num b
+    .tailcall 'infix:=='(a, b)
+.end
+
+
+=back
+
+=cut
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:

Added: trunk/languages/ecmascript/src/classes/Object.pir
==============================================================================
--- (empty file)
+++ trunk/languages/ecmascript/src/classes/Object.pir	Wed Dec 24 00:09:24 2008
@@ -0,0 +1,759 @@
+## $Id: Object.pir 34029 2008-12-17 15:28:47Z jonathan $
+
+=head1 TITLE
+
+Object - JS Object class
+
+=head1 DESCRIPTION
+
+This file sets up the base classes and methods for JS's
+object system.  Differences (and conflicts) between Parrot's
+object model and the JS model means we have to do a little
+name and method trickery here and there, and this file takes
+care of much of that.
+
+=cut
+
+.namespace []
+.sub '' :anon :init :load
+    .local pmc jsmeta
+    load_bytecode 'PCT.pbc'
+    $P0 = get_root_global ['parrot'], 'P6metaclass'
+    $P0.'new_class'('JSObject')
+    jsmeta = $P0.'HOW'()
+    set_hll_global ['JSObject'], '$!JSMETA', jsmeta
+.end
+
+=head2 Methods
+
+=over 4
+
+=item clone()
+
+Returns a copy of the object.
+
+NOTE: Don't copy what this method does; it's a tad inside-out. We should be
+overriding the clone vtable method to call .clone() really. But if we do that,
+we can't current get at the Object PMC's clone method, so for now we do it
+like this.
+
+=cut
+
+.namespace ['JSObject']
+.sub 'clone' :method
+    .param pmc new_attrs :slurpy :named
+
+    # Make a clone.
+    .local pmc result
+    $I0 = isa self, 'ObjectRef'
+    unless $I0 goto do_clone
+    self = deref self
+  do_clone:
+    result = clone self
+
+    # Set any new attributes.
+    .local pmc it
+    it = iter new_attrs
+  it_loop:
+    unless it goto it_loop_end
+    $S0 = shift it
+    $P0 = new_attrs[$S0]
+    $S0 = concat '!', $S0
+    $P1 = result.$S0()
+    'infix:='($P1, $P0)
+    goto it_loop
+  it_loop_end:
+
+    .return (result)
+.end
+
+
+=item defined()
+
+Return true if the object is defined.
+
+=cut
+
+.namespace ['JSObject']
+.sub 'defined' :method
+    $P0 = get_hll_global ['Bool'], 'True'
+    .return ($P0)
+.end
+
+
+=item hash
+
+Return invocant in hash context.
+
+=cut
+
+.namespace ['JSObject']
+.sub 'hash' :method
+    .tailcall self.'Hash'()
+.end
+
+.namespace []
+.sub 'hash'
+    .param pmc values :slurpy
+    .tailcall values.'Hash'()
+.end
+
+=item item
+
+Return invocant in item context.  Default is to return self.
+
+=cut
+
+.namespace ['JSObject']
+.sub 'item' :method
+    .return (self)
+.end
+
+.namespace []
+.sub 'item'
+    .param pmc x               :slurpy
+    $I0 = elements x
+    unless $I0 == 1 goto have_x
+    x = shift x
+  have_x:
+    $I0 = can x, 'item'
+    unless $I0 goto have_item
+    x = x.'item'()
+  have_item:
+    .return (x)
+.end
+
+
+=item list
+
+Return invocant in list context.  Default is to return a List containing self.
+
+=cut
+
+.namespace ['JSObject']
+.sub 'list' :method
+    $P0 = new 'List'
+    push $P0, self
+    .return ($P0)
+.end
+
+=item print()
+
+Print the object.
+
+=cut
+
+.namespace ['JSObject']
+.sub 'print' :method
+    $P0 = get_hll_global 'print'
+    .tailcall $P0(self)
+.end
+
+=item say()
+
+Print the object, followed by a newline.
+
+=cut
+
+.namespace ['JSObject']
+.sub 'say' :method
+    $P0 = get_hll_global 'say'
+    .tailcall $P0(self)
+.end
+
+=item true()
+
+Boolean value of object -- defaults to C<.defined> (S02).
+
+=cut
+
+.namespace ['JSObject']
+.sub 'true' :method
+    .tailcall self.'defined'()
+.end
+
+=back
+
+=head2 Coercion methods
+
+=over 4
+
+=item Array()
+
+=cut
+
+.namespace ['JSObject']
+.sub 'Array' :method
+    $P0 = new 'JSArray'
+    $P0.'!STORE'(self)
+    .return ($P0)
+.end
+
+=item Hash()
+
+=cut
+
+.namespace ['JSObject']
+.sub 'Hash' :method
+    $P0 = new 'JSHash'
+    $P0.'!STORE'(self)
+    .return ($P0)
+.end
+
+=item Iterator()
+
+=cut
+
+.sub 'Iterator' :method
+    $P0 = self.'list'()
+    .tailcall $P0.'Iterator'()
+.end
+
+=item Scalar()
+
+Default Scalar() gives reference type semantics, returning
+an object reference (unless the invocant already is one).
+
+=cut
+
+.namespace ['JSObject']
+.sub '' :method('Scalar') :anon
+    $I0 = isa self, 'ObjectRef'
+    unless $I0 goto not_ref
+    .return (self)
+  not_ref:
+    $P0 = new 'ObjectRef', self
+    .return ($P0)
+.end
+
+.namespace []
+.sub 'Scalar'
+    .param pmc source
+    $I0 = isa source, 'ObjectRef'
+    if $I0 goto done
+    $I0 = can source, 'Scalar'
+    if $I0 goto can_scalar
+    $I0 = does source, 'scalar'
+    source = new 'ObjectRef', source
+  done:
+    .return (source)
+  can_scalar:
+    .tailcall source.'Scalar'()
+.end
+
+=item Str()
+
+Return a string representation of the invocant.  Default is
+the object's type and address.
+
+=cut
+
+.namespace ['JSObject']
+.sub 'Str' :method
+    $P0 = new 'ResizableStringArray'
+    $P1 = self.'WHAT'()
+    push $P0, $P1
+    $I0 = get_addr self
+    push $P0, $I0
+    $S0 = sprintf "%s<0x%x>", $P0
+    .return ($S0)
+.end
+
+=back
+
+=head2 Special methods
+
+=over 4
+
+=item new()
+
+Create a new object having the same class as the invocant.
+
+=cut
+
+.namespace ['JSObject']
+.sub 'new' :method
+    .param pmc init_parents :slurpy
+    .param pmc init_this    :named :slurpy
+
+    # Instantiate.
+    .local pmc jsmeta
+    jsmeta = get_hll_global ['JSObject'], '$!JSMETA'
+    $P0 = jsmeta.'get_parrotclass'(self)
+    $P1 = new $P0
+
+    # If this proto object has a WHENCE auto-vivification, we should use
+    # put any values it contains but that init_this does not into init_this.
+    .local pmc whence
+    whence = self.'WHENCE'()
+    unless whence goto no_whence
+    .local pmc this_whence_iter
+    this_whence_iter = iter whence
+  this_whence_iter_loop:
+    unless this_whence_iter goto no_whence
+    $S0 = shift this_whence_iter
+    $I0 = exists init_this[$S0]
+    if $I0 goto this_whence_iter_loop
+    $P2 = whence[$S0]
+    init_this[$S0] = $P2
+    goto this_whence_iter_loop
+  no_whence:
+
+    # Now we will initialize each attribute in the class itself and it's
+    # parents with an Undef or the specified initialization value. Note that
+    # the all_parents list includes ourself.
+    .local pmc all_parents, class_iter
+    all_parents = inspect $P0, "all_parents"
+    class_iter = iter all_parents
+  class_iter_loop:
+    unless class_iter goto class_iter_loop_end
+    .local pmc cur_class
+    cur_class = shift class_iter
+
+    # If it's PMCProxy, then skip over it, since it's attribute is the delegate
+    # instance of a parent PMC class, which we should not change to Undef.
+    .local int is_pmc_proxy
+    is_pmc_proxy = isa cur_class, "PMCProxy"
+    if is_pmc_proxy goto class_iter_loop_end
+
+    # If this the current class?
+    .local pmc init_attribs
+    eq_addr cur_class, $P0, current_class
+
+    # If it's not the current class, need to see if we have any attributes.
+    # Go through the provided init_parents to see if we have anything that
+    # matches.
+    .local pmc ip_iter, cur_ip
+    ip_iter = iter init_parents
+  ip_iter_loop:
+    unless ip_iter goto ip_iter_loop_end
+    cur_ip = shift ip_iter
+
+    # We will check if their HOW matches.
+    $P2 = jsmeta.'get_parrotclass'(cur_ip)
+    eq_addr cur_class, $P2, found_parent_init
+
+    goto found_init_attribs
+  ip_iter_loop_end:
+
+    # If we get here, found nothing.
+    init_attribs = new 'Hash'
+    goto parent_init_search_done
+
+    # We found some parent init data, potentially.
+  found_parent_init:
+    init_attribs = cur_ip.'WHENCE'()
+    $I0 = 'defined'(init_attribs)
+    if $I0 goto parent_init_search_done
+    init_attribs = new 'Hash'
+  parent_init_search_done:
+    goto found_init_attribs
+
+    # If it's the current class, we will take the init_this hash.
+  current_class:
+    init_attribs = init_this
+  found_init_attribs:
+
+    # Now go through attributes of the current class and iternate over them.
+    .local pmc attribs, it
+    attribs = inspect cur_class, "attributes"
+    it = iter attribs
+  iter_loop:
+    unless it goto iter_end
+    $S0 = shift it
+
+    # See if we have an init value; use Undef if not.
+    .local int got_init_value
+    $S1 = substr $S0, 2
+    got_init_value = exists init_attribs[$S1]
+    if got_init_value goto have_init_value
+    $P2 = new 'Undef'
+    goto init_done
+  have_init_value:
+    $P2 = init_attribs[$S1]
+    delete init_attribs[$S1]
+  init_done:
+
+    # Is it a scalar? If so, want a scalar container with the type set on it.
+    .local string sigil
+    sigil = substr $S0, 0, 1
+    if sigil != '$' goto no_scalar
+    .local pmc attr_info, type
+    attr_info = attribs[$S0]
+    if null attr_info goto set_attrib
+    type = attr_info['type']
+    if null type goto set_attrib
+    if got_init_value goto no_proto_init
+    $I0 = isa type, 'P6protoobject'
+    unless $I0 goto no_proto_init
+    set $P2, type
+  no_proto_init:
+    $P2 = new 'JSScalar', $P2
+    setprop $P2, 'type', type
+    goto set_attrib
+  no_scalar:
+
+    # Is it an array? If so, initialize to JSArray.
+    if sigil != '@' goto no_array
+    $P3 = new 'JSArray'
+    $I0 = defined $P2
+    if $I0 goto have_array_value
+    set $P2, $P3
+    goto set_attrib
+  have_array_value:
+    'infix:='($P3, $P2)
+    set $P2, $P3
+    goto set_attrib
+  no_array:
+
+    # Is it a Hash? If so, initialize to JSHash.
+    if sigil != '%' goto no_hash
+    $P3 = new 'JSHash'
+    $I0 = defined $P2
+    if $I0 goto have_hash_value
+    set $P2, $P3
+    goto set_attrib
+  have_hash_value:
+    'infix:='($P3, $P2)
+    set $P2, $P3
+    goto set_attrib
+  no_hash:
+
+  set_attrib:
+    push_eh set_attrib_eh
+    setattribute $P1, cur_class, $S0, $P2
+  set_attrib_eh:
+    pop_eh
+    goto iter_loop
+  iter_end:
+
+    # Do we have anything left in the hash? If so, unknown.
+    $I0 = elements init_attribs
+    if $I0 == 0 goto init_attribs_ok
+    'die'("You passed an initialization parameter that does not have a matching attribute.")
+  init_attribs_ok:
+
+    # Next class.
+    goto class_iter_loop
+  class_iter_loop_end:
+
+    .return ($P1)
+.end
+
+=item 'PARROT'
+
+Report the object's true nature.
+
+=cut
+
+.sub 'PARROT' :method
+    .local pmc obj
+    .local string result
+    obj = self
+    result = ''
+    $I0 = isa obj, 'ObjectRef'
+    unless $I0 goto have_obj
+    result = 'ObjectRef->'
+    obj = deref obj
+  have_obj:
+    $P0 = typeof obj
+    $S0 = $P0
+    result .= $S0
+    .return (result)
+.end
+
+
+=item REJECTS(topic)
+
+Define REJECTS methods for objects (this would normally
+be part of the Pattern role, but we put it here for now
+until we get roles).
+
+=cut
+
+.sub 'REJECTS' :method
+    .param pmc topic
+    $P0 = self.'ACCEPTS'(topic)
+    n_not $P0, $P0
+    .return ($P0)
+.end
+
+
+=item WHENCE()
+
+Return the invocant's auto-vivification closure.
+
+=cut
+
+.sub 'WHENCE' :method
+    $P0 = self.'WHAT'()
+    $P1 = $P0.'WHENCE'()
+    .return ($P1)
+.end
+
+
+=item WHERE
+
+Gets the memory address of the object.
+
+=cut
+
+.sub 'WHERE' :method
+    $I0 = get_addr self
+    .return ($I0)
+.end
+
+
+=item WHICH
+
+Gets the object's identity value
+
+=cut
+
+.sub 'WHICH' :method
+    # For normal objects, this can just be the memory address.
+    .tailcall self.'WHERE'()
+.end
+
+=back
+
+=head2 Private methods
+
+=over 4
+
+=item !cloneattr(attrlist)
+
+Create a clone of self, also cloning the attributes given by attrlist.
+
+=cut
+
+.namespace ['JSObject']
+.sub '!cloneattr' :method
+    .param string attrlist
+    .local pmc jsmeta, result
+    jsmeta = get_hll_global ['JSObject'], '$!JSMETA'
+    $P0 = jsmeta.'get_parrotclass'(self)
+    result = new $P0
+
+    .local pmc attr_it
+    attr_it = split ' ', attrlist
+  attr_loop:
+    unless attr_it goto attr_end
+    $S0 = shift attr_it
+    unless $S0 goto attr_loop
+    $P1 = getattribute self, $S0
+    if null $P1 goto null_attr
+    $P1 = clone $P1
+  null_attr:
+    setattribute result, $S0, $P1
+    goto attr_loop
+  attr_end:
+    .return (result)
+.end
+
+=item !.?
+
+Helper method for implementing the .? operator. Calls at most one matching
+method, and returns undef if there are none.
+
+=cut
+
+.sub '!.?' :method
+    .param string method_name
+    .param pmc pos_args     :slurpy
+    .param pmc named_args   :slurpy :named
+
+    # Get all possible methods.
+    .local pmc methods
+    methods = self.'!MANY_DISPATCH_HELPER'(method_name, pos_args, named_args)
+
+    # Do we have any?
+    $I0 = elements methods
+    if $I0 goto invoke
+    .tailcall '!FAIL'('Undefined value returned by invocation of undefined method')
+
+    # If we do have a method, call it.
+  invoke:
+    $P0 = methods[0]
+    .tailcall self.$P0(pos_args :flat, named_args :named :flat)
+.end
+
+=item !.*
+
+Helper method for implementing the .* operator. Calls one or more matching
+methods.
+
+=cut
+
+.sub '!.*' :method
+    .param string method_name
+    .param pmc pos_args     :slurpy
+    .param pmc named_args   :slurpy :named
+
+    # Get all possible methods.
+    .local pmc methods
+    methods = self.'!MANY_DISPATCH_HELPER'(method_name, pos_args, named_args)
+
+    # Build result capture list.
+    .local pmc pos_res, named_res, cap, result_list, it, cur_meth
+    $P0 = get_hll_global 'list'
+    result_list = $P0()
+    it = iter methods
+  it_loop:
+    unless it goto it_loop_end
+    cur_meth = shift it
+    (pos_res :slurpy, named_res :named :slurpy) = cur_meth(self, pos_args :flat, named_args :named :flat)
+    cap = 'prefix:\\'(pos_res :flat, named_res :flat :named)
+    push result_list, cap
+    goto it_loop
+  it_loop_end:
+
+    .return (result_list)
+.end
+
+
+=item !.+
+
+Helper method for implementing the .+ operator. Calls one or more matching
+methods, dies if there are none.
+
+=cut
+
+.sub '!.+' :method
+    .param string method_name
+    .param pmc pos_args     :slurpy
+    .param pmc named_args   :slurpy :named
+
+    # Use !.* to produce a (possibly empty) list of result captures.
+    .local pmc result_list
+    result_list = self.'!.*'(method_name, pos_args :flat, named_args :flat :named)
+
+    # If we got no elements at this point, we must die.
+    $I0 = elements result_list
+    if $I0 == 0 goto failure
+    .return (result_list)
+  failure:
+    $S0 = "Could not invoke method '"
+    concat $S0, method_name
+    concat $S0, "' on invocant of type '"
+    $S1 = self.'WHAT'()
+    concat $S0, $S1
+    concat $S0, "'"
+    'die'($S0)
+.end
+
+
+=item !MANY_DISPATCH_HELPER
+
+This is a helper for implementing .+, .? and .*. In the future, it may well be
+the basis of WALK also. It returns all methods we could possible call.
+
+=cut
+
+.sub '!MANY_DISPATCH_HELPER' :method
+    .param string method_name
+    .param pmc pos_args
+    .param pmc named_args
+
+    # We need to find all methods we could call with the right name.
+    .local pmc jsmeta, result_list, class, mro, it
+    $P0 = get_hll_global 'list'
+    result_list = $P0()
+    jsmeta = get_hll_global ['JSObject'], '$!JSMETA'
+    class = self.'WHAT'()
+    class = jsmeta.'get_parrotclass'(class)
+    mro = inspect class, 'all_parents'
+    it = iter mro
+  mro_loop:
+    unless it goto mro_loop_end
+    .local pmc cur_class, meths, cur_meth
+    cur_class = shift it
+    meths = inspect cur_class, 'methods'
+    cur_meth = meths[method_name]
+    if null cur_meth goto mro_loop
+
+    # If we're here, found a method. But is it a multi?
+    $I0 = isa cur_meth, "JSMultiSub"
+    if $I0 goto multi_dispatch
+
+    # Single dispatch - add to the result list.
+    push result_list, cur_meth
+    goto mro_loop
+
+    # Multiple dispatch; get all applicable candidates.
+  multi_dispatch:
+    .local pmc possibles, possibles_it
+    possibles = cur_meth.'find_possible_candidates'(self, pos_args :flat)
+    possibles_it = iter possibles
+  possibles_it_loop:
+    unless possibles_it goto possibles_it_loop_end
+    cur_meth = shift possibles_it
+    push result_list, cur_meth
+    goto possibles_it_loop
+  possibles_it_loop_end:
+    goto mro_loop
+  mro_loop_end:
+
+    .return (result_list)
+.end
+
+=item !.^
+
+Helper for doing calls on the metaclass.
+
+=cut
+
+.sub '!.^' :method
+    .param string method_name
+    .param pmc pos_args     :slurpy
+    .param pmc named_args   :slurpy :named
+
+    # Get the HOW or the object and do the call on that.
+    .local pmc how
+    how = self.'HOW'()
+    .tailcall how.method_name(self, pos_args :flat, named_args :flat :named)
+.end
+
+=back
+
+=head2 Vtable functions
+
+=cut
+
+.namespace ['JSObject']
+.sub '' :vtable('decrement') :method
+    $P0 = self.'pred'()
+    'infix:='(self, $P0)
+    .return(self)
+.end
+
+.sub '' :vtable('defined') :method
+    $I0 = self.'defined'()
+    .return ($I0)
+.end
+
+.sub '' :vtable('get_bool') :method
+    $I0 = self.'true'()
+    .return ($I0)
+.end
+
+.sub '' :vtable('get_iter') :method
+    .tailcall self.'Iterator'()
+.end
+
+.sub '' :vtable('get_string') :method
+    $S0 = self.'Str'()
+    .return ($S0)
+.end
+
+.sub '' :vtable('increment') :method
+    $P0 = self.'succ'()
+    'infix:='(self, $P0)
+    .return(self)
+.end
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:

Added: trunk/languages/ecmascript/src/classes/Reference.pir
==============================================================================
--- (empty file)
+++ trunk/languages/ecmascript/src/classes/Reference.pir	Wed Dec 24 00:09:24 2008
@@ -0,0 +1,90 @@
+## $Id: Nil.pir 33898 2008-12-14 19:56:12Z pmichaud $
+
+=head1 NAME
+
+src/classes/Reference.pir - Reference objects
+
+=head1 DESCRIPTION
+
+=cut
+
+.namespace []
+
+.sub '' :anon :load :init
+    .local pmc jsmeta, nilproto
+    jsmeta = get_hll_global ['JSObject'], '$!JSMETA'
+    nilproto = jsmeta.'new_class'('Reference', 'parent'=>'Failure')
+    $P0 = nilproto.'new'()
+    set_hll_global ['Reference'], 'undef', $P0
+    .end
+.end
+
+=head2 Methods
+
+=over
+
+=item 'list'
+
+=cut
+
+.namespace ['Nil']
+.sub 'list' :method
+    $P0 = new 'List'
+    .return ($P0)
+.end
+
+
+=item 'shift'
+
+=cut
+
+.namespace ['Nil']
+.sub 'shift' :method :vtable('shift_pmc')
+    .return (self)
+.end
+
+=back
+
+=head2 Coercion methods
+
+=over
+
+=item Scalar
+
+=cut
+
+.namespace ['Nil']
+.sub 'Scalar' :method
+    $P0 = new 'Failure'
+    .return ($P0)
+.end
+
+
+=back
+
+=head2 Private methods
+
+=over
+
+=item !flatten
+
+Return an empty list when flattened.
+
+=cut
+
+.namespace ['Nil']
+.sub '!flatten' :method
+    .tailcall self.'list'()
+.end
+
+
+=back
+
+=cut
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
+

Added: trunk/languages/ecmascript/src/classes/String.pir
==============================================================================
--- (empty file)
+++ trunk/languages/ecmascript/src/classes/String.pir	Wed Dec 24 00:09:24 2008
@@ -0,0 +1,230 @@
+## $Id: Str.pir 33714 2008-12-09 16:57:49Z pmichaud $
+
+=head1 TITLE
+
+Str - JS Str class and related functions
+
+=head1 DESCRIPTION
+
+This file sets up the C<JSStr> PMC type (from F<src/pmc/jsstr.pmc>)
+as the JS C<Str> class.
+
+=head1 Methods
+
+=over 4
+
+=cut
+
+.namespace ['Str']
+
+.include 'cclass.pasm'
+
+.sub 'onload' :anon :init :load
+    .local pmc jsmeta, strproto
+    jsmeta = get_hll_global ['JSObject'], '$!JSMETA'
+    strproto = jsmeta.'new_class'('Str', 'parent'=>'JS6Str Any')
+    strproto.'!IMMUTABLE'()
+    jsmeta.'register'('JS6Str', 'parent'=>strproto, 'protoobject'=>strproto)
+    jsmeta.'register'('String', 'parent'=>strproto, 'protoobject'=>strproto)
+
+    $P0 = get_hll_namespace ['Str']
+    '!EXPORT'('sprintf,reverse', 'from'=>$P0)
+.end
+
+
+## special method to cast Parrot String into Rakudo Str.
+.namespace ['String']
+.sub 'Scalar' :method
+    $P0 = new 'Str'
+    assign $P0, self
+    copy self, $P0
+    .return (self)
+.end
+
+
+.namespace ['Str']
+.sub 'ACCEPTS' :method
+    .param string topic
+    .tailcall 'infix:eq'(topic, self)
+.end
+
+
+.sub 'reverse' :method :multi('String')
+    .local pmc retv
+
+    retv = self.'split'('')
+    retv = retv.'reverse'()
+    retv = retv.'join'('')
+
+    .return(retv)
+.end
+
+
+
+=item js()
+
+Returns a js representation of the Str.
+
+=cut
+
+.sub 'js' :method
+    .local string str, result
+    str = self
+    result = '"'
+    .local int pos
+    pos = 0
+    .local pmc arr
+    arr = new 'ResizablePMCArray'
+  loop:
+    .local string ch
+    ch = substr str, pos, 1
+    if ch == '' goto done
+    if ch == ' ' goto loop_ch
+    ##  check for special escapes
+    $I0 = index  "$ @ % & { \b \n \r \t \\ \"", ch
+    if $I0 < 0 goto loop_nonprint
+    ch = substr  "\\$\\@\\%\\&\\{\\b\\n\\r\\t\\\\\\\"", $I0, 2
+    goto loop_ch
+  loop_nonprint:
+    $I0 = is_cclass .CCLASS_PRINTING, ch, 0
+    if $I0 goto loop_ch
+    $I0 = ord ch
+    arr[0] = $I0
+    ch = sprintf '\x[%x]', arr
+  loop_ch:
+    result .= ch
+    inc pos
+    goto loop
+  done:
+    result .= '"'
+    .return (result)
+.end
+
+
+=item sprintf( *@args )
+
+=cut
+
+.sub 'sprintf' :method
+    .param pmc args            :slurpy
+    args.'!flatten'()
+    $P0 = new 'Str'
+    sprintf $P0, self, args
+    .return ($P0)
+.end
+
+
+=item WHICH()
+
+Returns the identify value.
+
+=cut
+
+.sub 'WHICH' :method
+    $S0 = self
+    .return ($S0)
+.end
+
+
+=back
+
+=head1 Functions
+
+=over 4
+
+=cut
+
+.namespace []
+
+.include 'cclass.pasm'
+
+
+=item infix:===
+
+Overridden for Str.
+
+=cut
+
+.namespace []
+.sub 'infix:===' :multi(String,String)
+    .param string a
+    .param string b
+    .tailcall 'infix:eq'(a, b)
+.end
+
+
+=back
+
+=head2 TODO Functions
+
+=over 4
+
+=item p5chop
+
+ our Char multi P5emul::Str::p5chop ( Str  $string is rw )
+ our Char multi P5emul::Str::p5chop ( Str *@strings = ($+_) is rw )
+
+Trims the last character from C<$string>, and returns it. Called with a
+list, it chops each item in turn, and returns the last character
+chopped.
+
+=item p5chomp
+
+ our Int multi P5emul::Str::p5chomp ( Str  $string is rw )
+ our Int multi P5emul::Str::p5chomp ( Str *@strings = ($+_) is rw )
+
+Related to C<p5chop>, only removes trailing chars that match C</\n/>. In
+either case, it returns the number of chars removed.
+
+=item chomp
+
+ our Str method Str::chomp ( Str $string: )
+
+Returns string with newline removed from the end.  An arbitrary
+terminator can be removed if the input filehandle has marked the
+string for where the "newline" begins.  (Presumably this is stored
+as a property of the string.)  Otherwise a standard newline is removed.
+
+Note: Most users should just let their I/O handles autochomp instead.
+(Autochomping is the default.)
+
+=item length
+
+This word is banned in JS.  You must specify units.
+
+=item index
+
+Needs to be in terms of StrPos, not Int.
+
+=item pack
+
+=item pos
+
+=item quotemeta
+
+=item rindex
+
+Needs to be in terms of StrPos, not Int.
+
+=item sprintf
+
+=item unpack
+
+=item vec
+
+Should replace vec with declared arrays of bit, uint2, uint4, etc.
+
+=item words
+
+ our List multi Str::words ( Rule $matcher = /\S+/,  Str $input = $+_, Int $limit = inf )
+ our List multi Str::words ( Str $input : Rule $matcher = /\S+/, Int $limit = inf )
+
+=back
+
+=cut
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:

Added: trunk/languages/ecmascript/src/classes/Undefined.pir
==============================================================================
--- (empty file)
+++ trunk/languages/ecmascript/src/classes/Undefined.pir	Wed Dec 24 00:09:24 2008
@@ -0,0 +1,90 @@
+## $Id: Nil.pir 33898 2008-12-14 19:56:12Z pmichaud $
+
+=head1 NAME
+
+src/classes/Nil.pir - Nil objects
+
+=head1 DESCRIPTION
+
+=cut
+
+.namespace []
+
+.sub '' :anon :load :init
+    .local pmc jsmeta, nilproto
+    jsmeta = get_hll_global ['JSObject'], '$!JSMETA'
+    nilproto = jsmeta.'new_class'('Nil', 'parent'=>'Failure')
+    $P0 = nilproto.'new'()
+    set_hll_global ['Undefined'], 'undef', $P0
+    .end
+.end
+
+=head2 Methods
+
+=over
+
+=item 'list'
+
+=cut
+
+.namespace ['Nil']
+.sub 'list' :method
+    $P0 = new 'List'
+    .return ($P0)
+.end
+
+
+=item 'shift'
+
+=cut
+
+.namespace ['Nil']
+.sub 'shift' :method :vtable('shift_pmc')
+    .return (self)
+.end
+
+=back
+
+=head2 Coercion methods
+
+=over
+
+=item Scalar
+
+=cut
+
+.namespace ['Nil']
+.sub 'Scalar' :method
+    $P0 = new 'Failure'
+    .return ($P0)
+.end
+
+
+=back
+
+=head2 Private methods
+
+=over
+
+=item !flatten
+
+Return an empty list when flattened.
+
+=cut
+
+.namespace ['Nil']
+.sub '!flatten' :method
+    .tailcall self.'list'()
+.end
+
+
+=back
+
+=cut
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
+

Modified: trunk/languages/ecmascript/src/parser/actions.pm
==============================================================================
--- trunk/languages/ecmascript/src/parser/actions.pm	(original)
+++ trunk/languages/ecmascript/src/parser/actions.pm	Wed Dec 24 00:09:24 2008
@@ -650,17 +650,21 @@
 
 method true($/) {
     # XXX change this into type a ECMAScript type, 'Boolean' or whatever
-    make PAST::Val.new( :returns('Integer'), :value('1'), :node($/) );
+#    make PAST::Val.new( :returns('Integer'), :value('1'), :node($/) );
+    make PAST::Var.new( :name(~$/), :namespace('JSBoolean'), :scope('package'), :node($/) );
+
 }
 
 method false($/) {
     # XXX change this into type 'Boolean' or whatever
-    make PAST::Val.new( :returns('Integer'), :value('0'), :node($/) );
+#    make PAST::Val.new( :returns('Integer'), :value('0'), :node($/) );
+    make PAST::Var.new( :name(~$/), :namespace('JSBoolean'), :scope('package'), :node($/) );
 }
 
 method null($/) {
     # XXX would this work?
     make PAST::Var.new( :name('null'), :scope('package'), :node($/) );
+#    make PAST::Var.new( :name(~$/), :namespace('Null'), :node($/) );
 }
 
 method object_literal($/) {

Modified: trunk/languages/ecmascript/src/parser/grammar.pg
==============================================================================
--- trunk/languages/ecmascript/src/parser/grammar.pg	(original)
+++ trunk/languages/ecmascript/src/parser/grammar.pg	Wed Dec 24 00:09:24 2008
@@ -441,8 +441,18 @@
 
 # whitespace rule used implicity by rules
 token ws {
-    | <!ww> <ws_all>+
-    | <ws_all>*
+  | <?{{  $P0 = get_global '$!ws'
+          if null $P0 goto noshort
+          $P1 = $P0.'to'()
+          $P2 = match.'to'()
+          if $P1 != $P2 goto noshort
+          .return (1)
+        noshort:
+          set_global '$!ws', match
+          .return (0)
+  }}>
+  | <!ww> <ws_all>+
+  | <ws_all>*
 }
 
 #### whitespace
@@ -597,8 +607,7 @@
 }
 
 rule call_expression {
-    <member_expression> <arguments> <post_call_expr>*
-    {*}
+    <member_expression> <arguments> <post_call_expr>* {*}
 }
 
 rule post_call_expr {

Added: trunk/languages/ecmascript/t/02-sanity-var.t
==============================================================================
--- (empty file)
+++ trunk/languages/ecmascript/t/02-sanity-var.t	Wed Dec 24 00:09:24 2008
@@ -0,0 +1,10 @@
+print("1..1\n");
+var STATUS = "STATUS: ";
+print("#");
+print(STATUS);
+print("\n");
+print("ok 1\n");
+
+/*
+ * vim: ft=javascript:
+ */

Added: trunk/languages/ecmascript/t/03-boolean.t
==============================================================================
--- (empty file)
+++ trunk/languages/ecmascript/t/03-boolean.t	Wed Dec 24 00:09:24 2008
@@ -0,0 +1,3 @@
+print(true);
+print(false);
+



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About