[svn:languages] r33 - in ecmascript: . branches tags trunk trunk/config trunk/config/makefiles trunk/lib trunk/lib/Parrot trunk/lib/Parrot/Test trunk/lib/Parrot/Test/JS trunk/src trunk/src/builtin trunk/src/classes trunk/src/parser trunk/t trunk/t/js_pt trunk/t/sanity_js trunk/t/sanity_pt

allison at svn.parrot.org allison at svn.parrot.org
Wed Mar 11 02:15:28 UTC 2009


Author: allison
Date: Wed Mar 11 02:15:26 2009
New Revision: 33
URL: https://trac.parrot.org/languages/changeset/33

Log:
[ecmascript] Relocating ECMAScript compiler to languages repository from
https://svn.parrot.org/parrot/trunk/languages/ecmascript/.

Added:
   ecmascript/
   ecmascript/branches/
   ecmascript/tags/
   ecmascript/trunk/
   ecmascript/trunk/MAINTAINER
   ecmascript/trunk/config/
   ecmascript/trunk/config/makefiles/
   ecmascript/trunk/config/makefiles/root.in
   ecmascript/trunk/js.pir
   ecmascript/trunk/lib/
   ecmascript/trunk/lib/Parrot/
   ecmascript/trunk/lib/Parrot/Test/
   ecmascript/trunk/lib/Parrot/Test/JS/
   ecmascript/trunk/lib/Parrot/Test/JS.pm
   ecmascript/trunk/lib/Parrot/Test/JS/PJS.pm
   ecmascript/trunk/lib/Parrot/Test/JS/SpiderMonkey.pm
   ecmascript/trunk/src/
   ecmascript/trunk/src/builtin/
   ecmascript/trunk/src/builtin/builtins.pir
   ecmascript/trunk/src/classes/
   ecmascript/trunk/src/classes/Array.pir
   ecmascript/trunk/src/classes/Boolean.pir
   ecmascript/trunk/src/classes/Completion.pir
   ecmascript/trunk/src/classes/List.pir
   ecmascript/trunk/src/classes/Null.pir
   ecmascript/trunk/src/classes/Number.pir
   ecmascript/trunk/src/classes/Object.pir
   ecmascript/trunk/src/classes/Reference.pir
   ecmascript/trunk/src/classes/String.pir
   ecmascript/trunk/src/classes/Undefined.pir
   ecmascript/trunk/src/parser/
   ecmascript/trunk/src/parser/actions.pm
   ecmascript/trunk/src/parser/grammar.pg
   ecmascript/trunk/t/
   ecmascript/trunk/t/00-comments.t
   ecmascript/trunk/t/01-literals.t
   ecmascript/trunk/t/02-operators.t
   ecmascript/trunk/t/02-sanity-var.t
   ecmascript/trunk/t/harness
   ecmascript/trunk/t/js_pt/
   ecmascript/trunk/t/js_pt/00-template.t
   ecmascript/trunk/t/js_pt/09-array.t
   ecmascript/trunk/t/js_pt/09-array_literals.t
   ecmascript/trunk/t/js_pt/10-version.t
   ecmascript/trunk/t/js_pt/11-global_object.t
   ecmascript/trunk/t/js_pt/12-regex.t
   ecmascript/trunk/t/sanity_js/
   ecmascript/trunk/t/sanity_pt/
   ecmascript/trunk/t/sanity_pt/00-literals.t
   ecmascript/trunk/t/sanity_pt/01-vars.t
   ecmascript/trunk/t/sanity_pt/03-boolean.t
   ecmascript/trunk/t/sanity_pt/05-objects.t

Added: ecmascript/trunk/MAINTAINER
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/MAINTAINER	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,4 @@
+# $Id: MAINTAINER 18122 2007-04-10 16:58:56Z bernhard $
+
+N: Kevin Tew
+E: kevintew at tewk.com

Added: ecmascript/trunk/config/makefiles/root.in
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/config/makefiles/root.in	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,177 @@
+# Copyright (C) 2006-2009, Parrot Foundation.
+# $Id: root.in 36833 2009-02-17 20:09:26Z allison $
+
+## arguments we want to run parrot with
+PARROT_ARGS =
+
+## configuration settings
+BUILD_DIR     = @build_dir@
+LOAD_EXT      = @load_ext@
+O             = @o@
+
+# Setup some commands
+LN_S          = @lns@
+PERL          = @perl@
+RM_F          = @rm_f@
+RM_RF         = @rm_rf@
+CP            = @cp@
+PARROT        = ../../parrot at exe@
+CAT           = @cat@
+BUILD_DYNPMC  = $(PERL) $(BUILD_DIR)/tools/build/dynpmc.pl
+RECONFIGURE   = $(PERL) $(BUILD_DIR)/tools/dev/reconfigure.pl
+#CONDITIONED_LINE(darwin):
+#CONDITIONED_LINE(darwin):# MACOSX_DEPLOYMENT_TARGET must be defined for OS X compilation/linking
+#CONDITIONED_LINE(darwin):export MACOSX_DEPLOYMENT_TARGET := @osx_version@
+
+## places to look for things
+PARROT_DYNEXT = $(BUILD_DIR)/runtime/parrot/dynext
+PGE_LIBRARY   = $(BUILD_DIR)/runtime/parrot/library/PGE
+PERL6GRAMMAR  = $(PGE_LIBRARY)/Perl6Grammar.pbc
+NQP           = $(BUILD_DIR)/compilers/nqp/nqp.pbc
+PCT           = $(BUILD_DIR)/runtime/parrot/library/PCT.pbc
+PBC_TO_EXE    = $(BUILD_DIR)/pbc_to_exe at exe@
+
+PMCDIR   = src/pmc
+
+
+# the default target
+all: js.pbc #$(PMCDIR)/js_group$(LOAD_EXT)
+
+SOURCES = \
+  js.pir \
+  src/gen_grammar.pir \
+  src/gen_actions.pir \
+  src/builtin/builtins.pir \
+  src/classes/Object.pir \
+  src/classes/Array.pir \
+  src/classes/Null.pir \
+  src/classes/Boolean.pir \
+  src/classes/Number.pir \
+  src/classes/String.pir \
+  src/classes/Undefined.pir \
+
+#PMCS = \
+#  jsobject \
+#  jsinteger \
+#  jshash \
+#  jsbignum \
+#  jscomplex \
+#  jsfixnum \
+#  jsfloat \
+#  jsstring
+
+#PMC_SOURCES = \
+#  $(PMCDIR)/jsobject.pmc \
+#  $(PMCDIR)/jsinteger.pmc \
+#  $(PMCDIR)/jshash.pmc \
+#  $(PMCDIR)/jsbignum.pmc \
+#  $(PMCDIR)/jscomplex.pmc \
+#  $(PMCDIR)/jsfixnum.pmc \
+#  $(PMCDIR)/jsfloat.pmc \
+#  $(PMCDIR)/jsstring.pmc
+
+#BUILTINS_PIR = \
+#  src/builtins/assign.pir \
+#  src/builtins/cmp.pir \
+#  src/builtins/io.pir
+
+#GEN_PIR = \
+#  src/js_grammar_gen.pir \
+#  src/ASTGrammar.pir \
+#  src/OSTGrammar.pir \
+#  src/builtins_gen.pir
+
+#GEN_PBC = \
+#  src/CardinalGrammar.pbc \
+#  src/PGE2AST.pbc \
+#  src/AST2OST.pbc \
+#  src/PAST.pbc \
+#  src/POST.pbc
+
+# target for building a standalone javascript compiler
+js at exe@: js.pbc
+	$(PBC_TO_EXE) js.pbc
+
+# the default target
+js.pbc: $(PARROT) $(SOURCES)
+	$(PARROT) $(PARROT_ARGS) -o js.pbc js.pir
+
+src/gen_grammar.pir: $(PERL6GRAMMAR) src/parser/grammar.pg
+	$(PARROT) $(PARROT_ARGS) $(PERL6GRAMMAR) \
+	    --output=src/gen_grammar.pir \
+	    src/parser/grammar.pg
+
+src/gen_actions.pir: $(NQP) $(PCT) src/parser/actions.pm
+	$(PARROT) $(PARROT_ARGS) $(NQP) --output=src/gen_actions.pir \
+	    --target=pir src/parser/actions.pm
+
+# no builtins yet
+#src/gen_builtins.pir: $(BUILTINS_PIR)
+#	$(CAT) $(BUILTINS_PIR) >src/gen_builtins.pir
+
+
+# regenerate the Makefile
+Makefile: config/makefiles/root.in
+	cd $(BUILD_DIR) && $(RECONFIGURE) --step=gen::languages --languages=ecmascript
+
+# This is a listing of all targets, that are meant to be called by users
+help:
+	@echo ""
+	@echo "Following targets are available for the user:"
+	@echo ""
+	@echo "  all:               js.pbc"
+	@echo "                     This is the default."
+	@echo "Testing:"
+	@echo "  test:              Run the test suite."
+	@echo "  testclean:         Clean up test results."
+	@echo ""
+	@echo "Cleaning:"
+	@echo "  clean:             Basic cleaning up."
+	@echo "  realclean:         Removes also files generated by 'Configure.pl'"
+	@echo "  distclean:         Removes also anything built, in theory"
+	@echo ""
+	@echo "Misc:"
+	@echo "  help:              Print this help message."
+	@echo ""
+
+test: all
+	$(PERL) t/harness
+
+testclean:
+	$(RM_F) "t/*.js" "t/*.out"
+	$(RM_F) "t/sanity_pt/*.js" "t/sanity_pt/*.out"
+	$(RM_F) "t/js_pt/*.js" "t/js_pt/*.out"
+
+
+CLEANUPS = \
+  js.pbc \
+  js at exe@ \
+  js.c \
+  src/gen_grammar.pir \
+  src/gen_actions.pir \
+  src/gen_builtins.pir \
+  $(PMCDIR)/*.h \
+  $(PMCDIR)/*.c \
+  $(PMCDIR)/*.dump \
+  $(PMCDIR)/*$(O) \
+  $(PMCDIR)/*$(LOAD_EXT) \
+  $(PMC_DIR)/*.exp \
+  $(PMC_DIR)/*.ilk \
+  $(PMC_DIR)/*.manifest \
+  $(PMC_DIR)/*.pdb \
+  $(PMC_DIR)/*.lib \
+  t/*.out \
+  t/*.rb
+
+clean:
+	$(RM_RF) $(CLEANUPS)
+
+realclean: clean
+	$(RM_RF) Makefile
+
+distclean: realclean
+
+# Local variables:
+#   mode: makefile
+# End:
+# vim: ft=make:

Added: ecmascript/trunk/js.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/js.pir	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,116 @@
+=head1 NAME
+
+js -- A compiler for js ECMAScript-262
+
+=head1 SYNOPSIS
+
+  $ ./parrot languages/emcascript/js.pir script.js
+
+=head1 DESCRIPTION
+
+js is a compiler for ECMAScript-262 (3rd edition) running on Parrot.
+
+=cut
+
+
+## Create a 'List' class; stolen from Rakudo.
+## At some point, this should be refactored/reused.
+##
+.HLL 'js'
+.namespace []
+.sub 'onload' :anon :load :init
+    load_bytecode 'PCT.pbc'
+    .local pmc parrotns, jsns, exports
+    parrotns = get_root_namespace ['parrot']
+    jsns = get_hll_namespace
+    exports = split ' ', 'PAST PCT PGE P6metaclass'
+    parrotns.'export_to'(jsns, exports)
+.end
+
+.sub '__onload' :load :init
+    $P0 = subclass 'ResizablePMCArray', 'List'
+.end
+
+## Methods for the List class
+##
+.namespace ['List']
+
+.sub 'elems' :method
+    $I0 = elements self
+    .return ($I0)
+.end
+
+.sub 'unshift' :method
+    .param pmc x
+    unshift self, x
+.end
+
+.sub 'shift' :method
+    .local pmc x
+    x = shift self
+    .return (x)
+.end
+
+
+
+
+.namespace ['JS';'Compiler']
+
+.loadlib 'js_group'
+
+.sub 'onload' :load :init :anon
+    load_bytecode 'PCT.pbc'
+
+    #.local pmc jsmeta
+    #jsmeta = get_hll_global ['JSObject'], '!JSMETA'
+    #jsmeta.'new_class'('JS::Compiler', 'parent'=>'PCT::HLLCompiler')
+
+    #.local pmc jsmeta
+    #jsmeta = get_hll_global ['JSObject'], '!JSMETA'
+    #jsmeta.'new_class'('JS::Compiler', 'parent'=>'PCT::HLLCompiler')
+
+    $P0 = get_hll_global ['PCT'], 'HLLCompiler'
+    $P1 = $P0.'new'()
+    $P1.'language'('JS')
+    $P0 = get_hll_namespace ['JS';'Grammar']
+    $P1.'parsegrammar'($P0)
+    $P0 = get_hll_namespace ['JS';'Grammar';'Actions']
+    $P1.'parseactions'($P0)
+
+    ## Create a list called '@?BLOCK' and store it, so it can
+    ## be used in the parse actions.
+    ##
+    $P0 = new 'List'
+    set_hll_global ['JS';'Grammar';'Actions'], '@?BLOCK', $P0
+
+.end
+
+
+.sub 'main' :main
+    .param pmc args
+    $P0 = compreg 'JS'
+    $P1 = $P0.'command_line'(args)
+.end
+
+
+.include 'src/gen_grammar.pir'
+.include 'src/gen_actions.pir'
+
+
+.namespace []
+
+.include 'src/builtin/builtins.pir'
+.include 'src/classes/Object.pir'
+.include 'src/classes/Array.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:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:

Added: ecmascript/trunk/lib/Parrot/Test/JS.pm
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/lib/Parrot/Test/JS.pm	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,64 @@
+# $Id: JS.pm 36833 2009-02-17 20:09:26Z allison $
+
+# Copyright (C) 2008, Parrot Foundation.
+
+package Parrot::Test::JS;
+
+# pragmata
+use strict;
+use warnings;
+
+use Data::Dumper;
+use File::Basename;
+use File::Spec;
+
+use Parrot::Test;
+use Parrot::Test::JS::SpiderMonkey;
+use Parrot::Test::JS::PJS;
+
+=head1 NAME
+
+Test/JS.pm - Testing routines specific to 'js'.
+
+=head1 DESCRIPTION
+
+Call 'js.pbc' and 'js'.
+
+=head1 METHODS
+
+=head2 new
+
+A kind of factory, that finds the proper subclass of Parrot::Test::JS.
+
+Use the executable B<js> in smoke testing.
+
+=cut
+
+sub new {
+    my $test_module =  $ENV{PARROT_PIPP_TEST_MODULE} || 'Parrot::Test::JS::PJS';
+
+    return bless {}, $test_module;
+}
+
+sub get_cd {
+    my $self = shift;
+    my ( $options ) = @_;
+
+    return File::Spec->catdir( $self->{relpath}, 'languages', 'ecmascript' );
+}
+
+sub get_lang_fn {
+    my $self = shift;
+    my ( $count, $options ) = @_;
+
+    return Parrot::Test::per_test( '.js', $count );
+}
+
+1;
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:

Added: ecmascript/trunk/lib/Parrot/Test/JS/PJS.pm
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/lib/Parrot/Test/JS/PJS.pm	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,49 @@
+# $Id: PJS.pm 36833 2009-02-17 20:09:26Z allison $
+
+# Copyright (C) 2008, Parrot Foundation.
+
+package Parrot::Test::JS::PJS;
+
+# pragmata
+use strict;
+use warnings;
+
+use base 'Parrot::Test::JS';
+
+# Generate output_is(), output_isnt() and output_like() in current package.
+Parrot::Test::generate_languages_functions();
+
+sub get_out_fn {
+    my $self = shift;
+    my ( $count, $options ) = @_;
+
+    return Parrot::Test::per_test( '_pjs.out', $count );
+}
+
+# Use JS on the command line
+sub get_test_prog {
+    my $self = shift;
+    my ( $count, $options ) = @_;
+
+    my $lang_fn = Parrot::Test::per_test( '.js', $count );
+    $lang_fn =~ s!^js/!!; # fix for unified languages testing
+
+    return "$self->{relpath}/parrot $self->{relpath}/languages/ecmascript/js.pbc ${lang_fn}";
+}
+
+# never skip the reference implementation
+sub skip_why {
+    my $self = shift;
+    my ($options) = @_;
+
+    return;
+}
+
+1;
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:

Added: ecmascript/trunk/lib/Parrot/Test/JS/SpiderMonkey.pm
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/lib/Parrot/Test/JS/SpiderMonkey.pm	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,48 @@
+# $Id: SpiderMonkey.pm 36833 2009-02-17 20:09:26Z allison $
+
+# Copyright (C) 2008, Parrot Foundation.
+
+package Parrot::Test::JS::SpiderMonkey;
+
+# pragmata
+use strict;
+use warnings;
+
+use base 'Parrot::Test::JS';
+
+# Generate output_is(), output_isnt() and output_like() in current package.
+Parrot::Test::generate_languages_functions();
+
+sub get_out_fn {
+    my $self = shift;
+    my ( $count, $options ) = @_;
+
+    return Parrot::Test::per_test( '_js.out', $count );
+}
+
+# Use SpiderMonkey on the command line
+sub get_test_prog {
+    my $self = shift;
+    my ( $count, $options ) = @_;
+
+    my $lang_fn = Parrot::Test::per_test( '.js', $count );
+
+    return "js $lang_fn";
+}
+
+# never skip the reference implementation
+sub skip_why {
+    my $self = shift;
+    my ($options) = @_;
+
+    return;
+}
+
+1;
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:

Added: ecmascript/trunk/src/builtin/builtins.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/src/builtin/builtins.pir	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,424 @@
+# Copyright (C) 2005-2008, Parrot Foundation.
+# $Id: builtins.pir 36833 2009-02-17 20:09:26Z allison $
+
+.include 'except_severity.pasm'
+
+## Not sure what standard built-in library is for ECMAScript, but
+## we need some output function for testing. For now this'll do.
+## Separate items with an space, as the js shell in SpiderMonkey do.
+
+.sub 'print'
+    .param pmc args :slurpy
+    .local pmc iter
+    new iter, 'Iterator', args
+    unless iter goto end_print_loop
+  print_loop:
+    $P1 = shift iter
+    print $P1
+    unless iter goto end_print_loop
+    print ' '
+    goto print_loop
+  end_print_loop:
+    print "\n"
+.end
+
+.sub 'quit'
+    .param pmc args :slurpy
+    .local int nargs, retcode
+    retcode = 0
+    nargs = args
+    unless nargs goto done
+    retcode = args [0]
+done:
+    # Severity doomed used to bypass the catching done
+    # by the default HLL compiler.
+    die .EXCEPT_DOOMED, retcode
+.end
+
+.sub 'readline'
+    .param pmc unused :slurpy
+    .local pmc stdin
+    stdin = getstdin
+    .local string line
+    line = readline stdin
+    .return(line)
+.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
+## what we want. For now.
+##
+.sub 'Object'
+    .param pmc fields :slurpy :named
+    .return (fields)
+.end
+
+
+#.sub 'Array'
+#    .param pmc args :slurpy
+#    $P0 = new 'Array'
+#    .return ($P0)
+#.end
+
+.sub __load :init :anon
+    newclass $P0, ['ECMAScript';'Object']
+    newclass $P1, ['ECMAScript';'Array']
+.end
+
+.namespace ['ECMAScript';'Object']
+
+
+
+.namespace ['ECMAScript';'Array']
+
+.sub 'Put' :method
+   .param pmc propname
+   .param pmc value
+   $I0 = self.'CanPut'(propname)
+   unless $I0 goto stop
+
+ stop:
+   .return()
+.end
+
+.sub 'CanPut' :method
+    .param pmc propname
+.end
+
+.sub 'Get' :method
+    .param pmc propname
+.end
+
+.namespace []
+
+## built-in functions
+##
+
+## probably add :vtable flag to these:
+##
+##.sub 'ToString' :multi(num)
+##    .param num arg
+##    #$P0 = new 'String'
+##    $S0 = arg
+##    .return ($S0)
+##.end
+##
+##.sub 'ToString' :multi(int)
+##    .param int arg
+##    #$P0 = new 'String'
+##    $S0 = arg
+##    .return ($S0)
+##.end
+##
+##.sub 'ToString' :multi(string)
+##    .param string arg
+##    .return (arg)
+##.end
+##
+##.sub 'ToString' :multi(_)
+##    .param pmc arg
+##    $S0 = arg
+##    .return ($S0)
+##.end
+
+
+
+## built-in operators
+##
+
+.sub 'prefix:?' :multi(_)
+    .param pmc a
+    if a goto a_true
+    $P0 = get_hll_global ['JSBoolean'], 'false'
+    .return ($P0)
+  a_true:
+    $P0 = get_hll_global ['JSBoolean'], 'true'
+    .return ($P0)
+.end
+
+.sub 'infix:='
+    .param pmc lhs
+    .param pmc rhs
+    assign lhs, rhs
+    .return (lhs)
+.end
+
+.sub 'infix:+='
+    .param pmc lhs
+    .param pmc rhs
+    add lhs, rhs
+    .return (lhs)
+.end
+
+.sub 'infix:-='
+    .param pmc lhs
+    .param pmc rhs
+    sub lhs, rhs
+    .return (lhs)
+.end
+
+.sub 'infix:*='
+    .param pmc lhs
+    .param pmc rhs
+    mul lhs, rhs
+    .return (lhs)
+.end
+
+.sub 'infix:/='
+    .param pmc lhs
+    .param pmc rhs
+    div lhs, rhs
+    .return (lhs)
+.end
+
+.sub 'infix:%='
+    .param pmc lhs
+    .param pmc rhs
+    mod lhs, rhs
+    .return (lhs)
+.end
+
+
+
+
+
+
+
+
+
+## postfix operators
+##
+.sub 'postfix:++'
+    .param pmc a
+    $P0 = clone a
+    inc a
+    .return ($P0)
+.end
+
+.sub 'postfix:--'
+    .param pmc a
+    $P0 = clone a
+    dec a
+    .return ($P0)
+.end
+
+## infix operators
+##
+
+#.sub 'infix:||'
+#    .param pmc left
+#    .param pmc right
+#.end
+#
+#
+#.sub 'infix:&&'
+#    .param pmc left
+#    .param pmc right
+#.end
+
+
+.sub 'infix:|'
+    .param pmc left
+    .param pmc right
+    $I1 = left
+    $I2 = right
+    bor $I0, $I1, $I2
+    .return ($I0)
+.end
+
+
+.sub 'infix:^'
+    .param pmc left
+    .param pmc right
+    $I1 = left
+    $I2 = right
+    bxor $I0, $I1, $I2
+    .return ($I0)
+.end
+
+
+.sub 'infix:&'
+    .param pmc left
+    .param pmc right
+    $I1 = left
+    $I2 = right
+    band $I0, $I1, $I2
+    .return ($I0)
+.end
+
+
+.sub 'infix:=='
+    .param pmc left
+    .param pmc right
+    iseq $I0, left, right
+    .tailcall 'prefix:?'($I0)
+.end
+
+
+.sub 'infix:!='
+    .param pmc left
+    .param pmc right
+    isne $I0, left, right
+    .return ($I0)
+.end
+
+
+.sub 'infix:==='
+    .param pmc left
+    .param pmc right
+.end
+
+
+.sub 'infix:!=='
+    .param pmc left
+    .param pmc right
+.end
+
+
+.sub 'infix:<'
+    .param pmc left
+    .param pmc right
+    $I0 = islt left, right
+    .return ($I0)
+.end
+
+
+.sub 'infix:>'
+    .param pmc left
+    .param pmc right
+    $I0 = isgt left, right
+    .return ($I0)
+.end
+
+.sub 'infix:<='
+    .param pmc left
+    .param pmc right
+    $I0 = isle left, right
+    .return ($I0)
+.end
+
+
+.sub 'infix:>='
+    .param pmc left
+    .param pmc right
+    $I0 = isge left, right
+    .return ($I0)
+.end
+
+
+.sub 'infix:instanceof'
+    .param pmc left
+    .param pmc right
+.end
+
+
+.sub 'infix:in'
+    .param pmc left
+    .param pmc right
+.end
+
+
+.sub 'infix:<<'
+    .param pmc left
+    .param pmc right
+.end
+
+
+.sub 'infix:>>'
+    .param pmc left
+    .param pmc right
+.end
+
+
+.sub 'infix:>>>'
+    .param pmc left
+    .param pmc right
+.end
+
+
+## prefix operators
+##
+.sub 'prefix:delete'
+    .param pmc op
+.end
+
+
+.sub 'prefix:void'
+    .param pmc op
+.end
+
+.sub 'prefix:typeof'
+    .param pmc op
+    $S0 = typeof op
+
+    $S1 = 'unknown'
+    ne $S0, 'Sub', n1
+    $S1 = 'function'
+    n1:
+
+    .return ($S1)
+.end
+
+.sub 'prefix:+'
+    .param pmc op
+    $N0 = op
+    .return ($N0)
+.end
+
+.sub 'prefix:-'
+    .param pmc op
+    $N0 = op
+    neg $N0
+    .return ($N0)
+.end
+
+.sub 'prefix:++'
+    .param pmc op
+    inc op
+    .return (op)
+.end
+
+.sub 'prefix:--'
+    .param pmc op
+    dec op
+    .return (op)
+.end
+
+.sub 'prefix:~'
+    .param pmc op
+    bnot $P0, op
+    .return ($P0)
+.end
+
+.sub 'prefix:!'
+    .param pmc op
+    istrue $I0, op
+    not $I0
+    .return ($I0)
+.end
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:

Added: ecmascript/trunk/src/classes/Array.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/src/classes/Array.pir	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,351 @@
+## $Id: Array.pir 35477 2009-01-13 05:36:01Z tewk $
+
+=head1 TITLE
+
+Object - JS Array 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'('Array', 'parent'=>'JSObject')
+    jsmeta = $P0.'HOW'()
+    set_hll_global ['Array'], '$!JSMETA', jsmeta
+    get_class $P0, 'Array'
+    addattribute $P0, '__array'
+.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 ['Array']
+.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 ['Array']
+.sub 'defined' :method
+    $P0 = get_hll_global ['Bool'], 'True'
+    .return ($P0)
+.end
+
+
+=item hash
+
+Return invocant in hash context.
+
+=cut
+
+.namespace ['Array']
+.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 ['Array']
+.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 ['Array']
+.sub 'list' :method
+    $P0 = new 'List'
+    push $P0, self
+    .return ($P0)
+.end
+
+=item print()
+
+Print the object.
+
+=cut
+
+.namespace ['Array']
+.sub 'print' :method
+    $P0 = get_hll_global 'print'
+    .tailcall $P0(self)
+.end
+
+=item say()
+
+Print the object, followed by a newline.
+
+=cut
+
+.namespace ['Array']
+.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 ['Array']
+.sub 'true' :method
+    .tailcall self.'defined'()
+.end
+
+=back
+
+=head2 Coercion methods
+
+=over 4
+
+=item Array()
+
+=cut
+
+.namespace ['Array']
+.sub 'Array' :method
+    $P0 = new 'Array'
+    $P0.'!STORE'(self)
+    .return ($P0)
+.end
+
+=item Hash()
+
+=cut
+
+.namespace ['Array']
+.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 ['Array']
+.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 ['Array']
+.sub 'Str' :method
+    $P0 = new 'ResizableStringArray'
+    $P1 = self.'WHAT'()
+    push $P0, $P1
+    $I0 = get_addr self
+    push $P0, $I0
+    #$S0 = sprintf "[object Object %s 0x%x]", $P0
+    $S0 = sprintf "[object Object]", $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 ['Array']
+.sub 'new' :method
+    .param pmc init_parents :slurpy
+    .param pmc init_this    :named :slurpy
+
+    # Instantiate.
+    .local pmc jsmeta
+    jsmeta = get_hll_global ['Array'], '$!JSMETA'
+    $P0 = jsmeta.'get_parrotclass'(self)
+    $P1 = new $P0
+    .return ($P1)
+.end
+
+=back
+
+=head2 Vtable functions
+
+=cut
+
+.namespace ['Array']
+.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('get_string') :method
+    $S0 = ''
+    .local pmc iter
+    iter = new 'Iterator', self
+    goto loop_start
+    loop:
+    unless iter goto end
+    $S0 = concat $S0, ','
+    loop_start:
+    $S1 = shift iter
+    $S2 = iter[$S1]
+    concat $S0, $S2
+    goto loop
+    end:
+.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: ecmascript/trunk/src/classes/Boolean.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/src/classes/Boolean.pir	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,76 @@
+## $Id: Boolean.pir 36388 2009-02-05 23:01:54Z NotFound $
+
+=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, booleanclass
+    booleanclass = get_root_global ['parrot'], 'Boolean'
+    jsmeta = get_hll_global ['JSObject'], '$!JSMETA'
+    boolproto = jsmeta.'new_class'('JSBoolean', 'parent'=>booleanclass)
+    #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
+   $I0 = self
+   unless self goto f
+  .return ("true")
+  f:
+  .return ("false")
+.end
+
+.sub 'get_integer1' #:vtable
+  .param pmc self
+   $I0 = self
+  .return ($I0)
+.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: ecmascript/trunk/src/classes/Completion.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/src/classes/Completion.pir	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,90 @@
+## $Id: Completion.pir 34337 2008-12-24 14:07:26Z bernhard $
+
+=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: ecmascript/trunk/src/classes/List.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/src/classes/List.pir	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,90 @@
+## $Id: List.pir 34337 2008-12-24 14:07:26Z bernhard $
+
+=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: ecmascript/trunk/src/classes/Null.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/src/classes/Null.pir	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,92 @@
+## $Id: Null.pir 35477 2009-01-13 05:36:01Z tewk $
+
+=head1 NAME
+
+src/classes/Nil.pir - Nil objects
+
+=head1 DESCRIPTION
+
+=cut
+
+.namespace []
+
+.sub '' :anon :load :init
+    .local pmc jsmeta, nilproto, nullclass
+    nullclass = get_hll_global ['parrot'], 'Null'
+    jsmeta = get_hll_global ['JSObject'], '$!JSMETA'
+    nilproto = jsmeta.'new_class'('JSNull', 'parent'=>nullclass)
+    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: ecmascript/trunk/src/classes/Number.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/src/classes/Number.pir	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,104 @@
+## $Id: Number.pir 34337 2008-12-24 14:07:26Z bernhard $
+
+=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: ecmascript/trunk/src/classes/Object.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/src/classes/Object.pir	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,791 @@
+## $Id: Object.pir 35787 2009-01-20 04:17:21Z chromatic $
+
+=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'
+    $P1 = get_root_global ['parrot'], 'Hash'
+    $P0 = get_root_global ['parrot'], 'P6metaclass'
+    $P0.'new_class'('JSObject', 'parent'=>$P1)
+    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 'Set' :method
+    .param pmc key
+    .param pmc val
+    self[key] = val
+    .return(self)
+.end
+
+.namespace ['JSObject']
+.sub 'Get' :method
+    .param pmc key
+    .local pmc val
+    val = self[key]
+    .return(val)
+.end
+
+.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 "[object Object %s 0x%x]", $P0
+    $S0 = sprintf "[object Object]", $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
+    .return ($P1)
+.end
+
+.sub 'old_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
+    goto no_whence
+    #.return ($P1)
+
+    # 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 'Hash'
+    $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)
+    $P1 = not $P0
+    .return ($P1)
+.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: ecmascript/trunk/src/classes/Reference.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/src/classes/Reference.pir	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,90 @@
+## $Id: Reference.pir 34337 2008-12-24 14:07:26Z bernhard $
+
+=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: ecmascript/trunk/src/classes/String.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/src/classes/String.pir	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,230 @@
+## $Id: String.pir 34337 2008-12-24 14:07:26Z bernhard $
+
+=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: ecmascript/trunk/src/classes/Undefined.pir
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/src/classes/Undefined.pir	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,90 @@
+## $Id: Undefined.pir 34337 2008-12-24 14:07:26Z bernhard $
+
+=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:
+

Added: ecmascript/trunk/src/parser/actions.pm
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/src/parser/actions.pm	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,811 @@
+# Copyright (C) 2008-2009, Parrot Foundation.
+# $Id: actions.pm 36833 2009-02-17 20:09:26Z allison $
+
+class JS::Grammar::Actions;
+
+method TOP($/, $key) {
+    our $?BLOCK;
+    our @?BLOCK;
+
+    if $key eq 'open' {
+        ## create a 'global' current block and stuff it into the scope stack.
+        $?BLOCK := PAST::Block.new( :blocktype('declaration'), :node($/) );
+        $?BLOCK.hll('js');
+
+        @?BLOCK.unshift($?BLOCK);
+    }
+    elsif $key eq 'close' {
+        # retrieve the current block from the scope stack
+        my $past := @?BLOCK.shift();
+        for $<source_element> {
+            $past.push( $( $_ ) );
+        }
+        make $past;
+    }
+}
+
+method source_element($/, $key) {
+    make $( $/{$key} );
+}
+
+method function_common($/) {
+    our @?BLOCK;
+    our $?BLOCK;
+
+    my $past := $( $<formal_parameter_list> );
+
+    ## only after having parsed the block can we get its PAST;
+    ## this is just a Stmts node, the function body.
+    $past.push( $( $<block> ) );
+
+    ## remove the current block from the scope stack; restore
+    ## the current block to the "previous" block, at the top of
+    ## the stack (position 0).
+    @?BLOCK.shift();
+    $?BLOCK := @?BLOCK[0];
+
+    $past.control('return_pir');
+
+    make $past;
+}
+
+method formal_parameter_list($/) {
+    our $?BLOCK;
+    our @?BLOCK;
+
+    ## the only place for formal parameters to live is in a function
+    ## block object, so create it here already. It can be decorated
+    ## with other function stuff when handling function_common.
+    my $past := PAST::Block.new( :blocktype('declaration'), :node($/) );
+
+    ## set the 'current' block to this $past, and stuff it onto the
+    ## scope stack (in case of nested functions).
+    $?BLOCK := $past;
+    @?BLOCK.unshift($past);
+
+    for $<identifier> {
+        my $parameter := $( $_ );
+        $parameter.scope('parameter');
+        ## register the parameter as a local variable.
+        $?BLOCK.symbol( $parameter.name(), :scope('lexical') );
+        $past.push($parameter);
+    }
+    make $past;
+}
+
+method function_declaration($/) {
+    my $past := $( $<function_common> );
+    $past.name( $( $<identifier> ).name() );
+    make $past
+}
+
+method function_expression( $/) {
+    my $past := $( $<function_common> );
+    if $<identifier> {
+        my $id := $( $<identifier>[0] );
+        # set id as a property
+
+        # set attributes DontDelete and ReadOnly; see ref.pdf, p.83.
+    }
+    make $past;
+}
+
+method statement($/, $key) {
+    make $( $/{$key} );
+}
+
+method statements($/) {
+    my $past := PAST::Stmts.new( :node($/) );
+    for $<statement> {
+        $past.push( $($_) );
+    }
+    make $past;
+}
+
+method block($/) {
+    ## Just any block does not define a different scope, so don't
+    ## create a PAST::Block. In cases where this is needed (functions)
+    ## a block can be wrapped around this Stmts node.
+    make $( $<statements> );
+}
+
+method if_statement($/) {
+    my $cond := $( $<expression> );
+    my $then := $( $<statement> );
+    my $past := PAST::Op.new( $cond, $then, :pasttype('if'), :node($/) );
+    if $<else> {
+        $past.push( $( $<else>[0] ) );
+    }
+    make $past;
+}
+
+method do_while_statement($/) {
+    my $cond := $( $<expression> );
+    my $block := $( $<statement> );
+    make PAST::Op.new( $cond, $block, :pasttype('repeat_while'), :node($/) );
+}
+
+method while_statement($/) {
+    my $cond := $( $<expression> );
+    my $block := $( $<statement> );
+    make PAST::Op.new( $cond, $block, :pasttype('while'), :node($/) );
+}
+
+## for1_statement: for ( <init>? ; <cond>? ; <step>? ) <statement>
+##
+## translates to:
+##
+## <init>
+## while (<cond>) {
+##   <statement>
+##   <step>
+## }
+##
+sub c_style_for($/,$var_decl) {
+
+    ## if there are variable declarations in the init portion of the C-style
+    ## for loop, we have to evaluate it first so that they are available
+    ## during the rest of loop
+    my $init;
+    if $var_decl {
+        $init := $( $<init> );
+    }
+    else {
+        if $<init> { $init := $( $<init>[0] ); }
+    }
+
+    my $body := $( $<statement> );
+
+    ## if there's a step, create a new compound statement node,
+    ## which consists of the pair ($body, $step).
+    if $<step> {
+        my $step := $( $<step>[0] );
+        $body := PAST::Stmts.new( $body, $step, :node($/) );
+    }
+
+    ## if there's a condition, get that expression; if there is none,
+    ## a 'true' condition is implicit, so create this value, in this
+    ## case the number '1'.
+    my $cond;
+    if $<cond> {
+        $cond := $( $<cond>[0] );
+    }
+    else {
+        $cond := PAST::Val.new( :value('1'), :returns('Integer'), :node($/) );
+    }
+
+    ## now create a while loop, giving it the condition and body.
+    my $loop := PAST::Op.new( $cond, $body, :pasttype('while'), :node($/) );
+
+    ## if there's an init step, it is evaluated before the loop, so
+    ## create a compound statement node ($init, $loop).
+    if $init {
+        $loop := PAST::Stmts.new( $init, $loop, :node($/) );
+    }
+    make $loop;
+}
+
+method for1_statement($/) {
+    c_style_for($/,0);
+}
+
+method for2_statement($/) {
+    # XXX todo
+    my $past;
+    my $body := $( $<statement> );
+    $past := $body;
+    make $past;
+}
+
+method for3_statement($/) {
+    # XXX todo
+    my $past;
+    my $body := $( $<statement> );
+    $past := $body;
+    make $past;
+}
+
+method for4_statement($/) {
+    c_style_for($/,1);
+}
+
+method labelled_statement($/) {
+    # XXX labels dont work properly.
+    my $label   := $( $<identifier> ).name() ~ ':' ;
+    my $labelop := PAST::Op.new( :inline($label), :node($/) );
+    my $stat    := $( $<statement> );
+    make PAST::Stmts.new( $labelop, $stat, :node($/) );
+}
+
+method continue_statement($/) {
+    # XXX todo
+    my $jumpop := '    goto LXXX';
+    make PAST::Op.new( :inline($jumpop), :node($/) );
+}
+
+method break_statement($/) {
+    # XXX todo
+    my $jumpop := '    goto LXXX';
+    make PAST::Op.new( :inline($jumpop), :node($/) );
+}
+
+method try_statement($/) {
+    my $past := PAST::Op.new( :pasttype('try'), :node($/) );
+    my $tryblock := $( $<block> );
+    $past.push($tryblock);
+
+    if $<catch> {
+        my $catchblock := $( $<catch> );
+        $past.push($catchblock);
+    }
+    if $<finally> {
+        ## the finally block, if present, is always executed.
+        my $finallyblock := $( $<finally> );
+        $past := PAST::Stmts.new( $past, $finallyblock, :node($/) );
+    }
+    make $past;
+}
+
+method catch($/) {
+   my $past := $( $<block> );
+   my $exid := $( $<identifier> );
+   ##  Add a catch node to the try op that captures the
+   ##  exception object into the declared identifier. Thanks to Rakudo for this trick.
+   my $catchpir := "    .get_results (%r)\n    store_lex '" ~ $exid.name() ~ "', %r";
+   $past.unshift( PAST::Op.new( :inline( $catchpir ) ) );
+   make $past;
+}
+
+method finally($/) {
+    make $( $<block> );
+}
+
+method throw_statement($/) {
+    my $expr := $( $<expression> );
+    make PAST::Op.new( $expr, :inline('    throw %0'), :node($/) );
+}
+
+method return_statement($/) {
+    my $past := PAST::Op.new( :pasttype('return'), :node($/) );
+    if $<expression> {
+        my $expr := $( $<expression>[0] );
+        $past.push($expr);
+    }
+    make $past;
+}
+
+method variable_declaration_list($/) {
+    ## each variable declared in this statement becomes a separate PIR
+    ## statement; therefore create a Stmts node.
+    my $past := PAST::Stmts.new( :node($/) );
+    for $<variable_declaration> {
+        $past.push( $( $_ ) );
+    }
+    make $past;
+}
+
+method variable_statement($/) {
+    make $( $<variable_declaration_list> )
+}
+
+method variable_declaration($/) {
+    our $?BLOCK;
+
+    my $var  := $( $<identifier> );
+    my $name := $var.name();
+    $var.isdecl(1);
+    $var.scope('lexical');
+
+    if $?BLOCK.symbol( $name ) {
+        ## XXX warning of duplicate declaration?
+    }
+    else { ## enter it if it's not there yet
+        $?BLOCK.symbol( $name, :scope('lexical') );
+    }
+
+    ## handle initialization value
+    if $<assignment_expression> {
+        my $initval := $( $<assignment_expression>[0] );
+        $var.viviself($initval);
+    }
+    else {
+        $var.viviself('Undef'); # XXX should be JavaScript undefined.
+    }
+
+    make $var;
+}
+
+method empty_statement($/) {
+    ## to prevent special cases for the empty statement, just create a comment.
+    make PAST::Op.new( :node($/), :inline('    # empty statement') );
+}
+
+method expression_statement($/) {
+    make $( $<expression> );
+}
+
+method switch_statement($/) {
+    # XXX fix this.
+    my $past := PAST::Stmts.new( :node($/) );
+    my $expr := $( $<expression> );
+
+    for $<case_block><case_clause> {
+        # get the 'if' statement that implements the case semantics
+        my $case := $($_);
+        # set the switch expression as the second child of the
+        # condition of the 'if' statement, which is the first child
+        # at index 0.
+        $case[0].push($expr);
+
+        # add this case to the list of statements
+        $past.push($case);
+    }
+
+    if $<case_block><default_clause> {
+        my $defaultcase := $( $<case_block><default_clause>[0] );
+
+        # XXX what to do with it? How to execute this only if the other
+        # cases failed?
+        $past.push($defaultcase);
+    }
+
+    make $past;
+}
+
+
+method case_clause($/) {
+    ## XXX this needs rework.
+    ## How to fall through the cases?
+    ## How to exit when a "break" statement is parsed?
+    ##
+    my $expr := $( $<expression> );
+    my $past := PAST::Op.new( :pasttype('if'), :node($/) );
+
+    ## this is taken from rakudo:
+    my $match_past := PAST::Op.new( :name('infix:~~'),
+                                    :pasttype('call'),
+                                    :node($/)
+                                  );
+
+    # set the "case" expression as the first child of the infix:~~
+    # operator; the expression that is "matched" is available in
+    # the method "switch_statement".
+    $match_past.push($expr);
+
+    # set the (incomplete) match_past as the condition for the
+    # if statement. this will be completed in the top-level rule.
+    $past.push($match_past);
+
+    my $stmts := $( $<statements> );
+
+    # set this block of statements as the 'if' block.
+    $past.push($stmts);
+
+    make $past;
+}
+
+method default_clause($/) {
+    make $( $<statements> );
+}
+
+method with_statement($/) {
+    ## XXX incomplete
+    my $past;
+
+    my $expr := $( $<expression> );
+    # call GetValue on $expr (ecmascript reference p.68)
+    my $val  := PAST::Op.new( $expr, :name('GetValue'), :pasttype('call'), :node($/) );
+    # call ToObject on this result
+    my $obj  :=PAST::Op.new( $val, :name('ToObject'), :pasttype('call'), :node($/) );
+
+    # XXX how to add this obj to the "scope chain"??
+    my $stat := $( $<statement> );
+
+    # XXX for now, set past just to stat.
+    $past := $stat;
+
+    make $past;
+}
+
+method primary_expression($/, $key) {
+    make $( $/{$key} );
+}
+
+method regular_expression_literal ($/) {
+    make PAST::Val.new( :value( ~$<regular_expression_literal> ), :node($/) );
+}
+
+method this($/) {
+    ## XXX wait for PAST support for 'self'
+    ## load 'self' into a register; when this PAST node is used as a child somewhere
+    ## this register will be used. This step is superfluous, but PAST does not support
+    ## PIR's 'self' special variable.
+    make PAST::Op.new( :inline('    %r = self'), :node($/) );
+}
+
+method call_expression($/) {
+    my $invocant := $( $<member_expression> );
+
+    ## the $<arguments> rule already creates a :pasttype('call') node.
+    my $past := $( $<arguments> );
+    $past.unshift($invocant);
+
+    for $<post_call_expr> {
+        my $postexpr := $( $_ );
+
+        ## the $invocant of this $postexpr is $past; set it as the first
+        ## child, so that it is evaluated first, and then invoked.
+        $postexpr.unshift($past);
+
+        ## make it work in a chain, like foo()()()(); In case the loop ends
+        ## here, $postexpr is the argument to "make"; otherwise, it's unshifted
+        ## onto the next $postexpr as the first child.
+        $past := $postexpr;
+    }
+
+    make $past;
+}
+
+method post_call_expr($/, $key) {
+    make $( $/{$key} );
+}
+
+method assignment_expression_X($/) {
+    my $past := $( $<conditional_expression> );
+
+    ## get number of lhs_expressions
+    my $lhsexpr := +$<lhs_expression>;
+
+    ## assignments such as 'a=b=c' are evaluated from right to left
+    ## first c is assigned to b, that result (b) is assigned to a.
+    ## therefore, loop through the array backwards.
+    while $lhsexpr != 0 {
+        $lhsexpr := $lhsexpr - 1;
+
+        ## generate the name of the assignment operator: 'infix:<operator>'
+        my $op  := 'infix:' ~ ~$<assignop>[$lhsexpr];
+        my $lhs := $( $<lhs_expression>[$lhsexpr] );
+
+        ## invoke this operator-sub, with $lhs and the $past so far as left/right operands.
+
+        if $op eq 'infix:=' {          # XXX += and friends won't work this way; solve that
+            $past   := PAST::Op.new( $lhs, $past, :pasttype('bind'), :node($/) );
+        }
+        else {
+            $past   := PAST::Op.new( $lhs, $past, :name($op), :pasttype('call'), :node($/) );
+        }
+
+        ## maybe a lookup table, mapping "+=" to "add" etc.
+
+    }
+    make $past;
+}
+
+method conditional_expression($/) {
+    my $past  := $( $<logical_or_expression> );
+
+    ## handle the "? :" ternary operator if present
+    if $<then> {
+        $past := PAST::Op.new(  $past,
+                                $( $<then>[0] ),
+                                $( $<else>[0] ),
+                                :pasttype('if'),
+                                :node($/) );
+    }
+    make $past;
+}
+
+method unary_expression($/) {
+    my $past := $( $<postfix_expression> );
+    my $unop := +$<unop>;
+
+    while $unop != 0 {
+        ## get the operators in reverse order, that is closest to
+        ## the operand (postfix_expression)
+        $unop  := $unop - 1;
+        my $op := $( $<unop>[$unop] );
+
+        ## set the current $past as the operand for that operation
+        $op.push($past);
+
+        ## and update $past for the next one (or for the make statement)
+        $past := $op;
+    }
+    make $past;
+}
+
+method unop($/) {
+    ## create a call op to invoke the specified unary operand.
+    ## this unary operator is named 'prefix:<operator>'.
+    my $operator := 'prefix:' ~ ~$<op>;
+    make PAST::Op.new( :name($operator), :pasttype('call'), :node($/) );
+}
+
+method postfix_expression($/) {
+    my $past := $( $<lhs_expression> );
+    if $<postfixop> {
+        ## create a string "postfix:++" or "postfix:--"
+        my $postfixop := 'postfix:' ~ ~$<postfixop>[0];
+
+        ## create an invocation of this operator, providing
+        ## the <lhs_expression> as its operand
+        $past := PAST::Op.new( $past,
+                               :pasttype('call'),
+                               :name($postfixop),
+                               :node($/)
+                             );
+    }
+    make $past;
+}
+
+method arguments($/) {
+    ## an arguments node always implies a function call;
+    ## create it here; unshift the invocant later when it's available.
+    my $past := PAST::Op.new( :pasttype('call'), :node($/) );
+
+    ## push all arguments onto this 'call' op.
+    for $<assignment_expression> {
+        $past.push( $($_) );
+    }
+    make $past;
+}
+
+method expression($/) {
+    ## and expression is a comma-separated list of assignment_expressions;
+    ## in other words, just a list of statements. Coincidentally, the
+    ## result of the last assignment_expression is returned, which is
+    ## exactly what is specified by ECMAScript.
+    my $past := PAST::Stmts.new( :node($/) );
+    for $<assignment_expression> {
+        $past.push( $( $_ ) );
+    }
+    make $past;
+}
+
+method lhs_expression($/, $key) {
+    make $( $/{$key} );
+}
+
+method member_expressionX($/) {
+    my $member := $( $<member_prefix> );
+
+    ## if there are any arguments, $member is invoked with these arguments.
+    if $<arguments> {
+        ## the <arguments> node creates the :pasttype('call') op
+        my $past := $( $<arguments> );
+
+        ## set $member as the first child which implies it's the invocant.
+        $past.unshift($member);
+        make $past;
+    }
+    else {
+        make $member;
+    }
+}
+
+method member_expression($/) {
+    my $past := $( $<member_prefix> );
+
+    ## for each index, $past acts as the invocant or main object on
+    ## which some operation is executed; therefore $past must be the
+    ## first child, so unshift it. Then, $past is assigned this result
+    ## preparing for either the next index or as argument for 'make'.
+    for $<member_suffix> {
+        my $idx := $( $_ );
+        $idx.unshift($past);
+        $past := $idx;
+    }
+
+    make $past;
+}
+
+method member_prefix($/, $key) {
+    make $( $/{$key} );
+}
+
+method member_suffix($/, $key) {
+    ## get the index expression
+    my $idx := $( $/{$key} );
+
+    ## create a keyed access operation, setting the expression as a child
+    ## the object to be indexed will be unshifted on this node, effectively
+    ## acting as the container (the first child). Neat huh?
+    my $past := PAST::Var.new( $idx, :scope('keyed'), :node($/) );
+
+    ## XXX Maybe an index should be handled by an operation, so that the
+    ## past must become a PAST::Op( :pasttype('call') ... ). Think of this later.
+    make $past;
+}
+
+method identifier_field($/) {
+    ## an identifier field is an identifier that is auto-quoted; it's a field
+    ## as in: foo.bar, which means foo["bar"]. Therefore, make a string from
+    ## this identifier.
+    my $id := $( $<identifier> );
+    make PAST::Val.new( :returns('String'), :value($id.name()), :node($/) );
+}
+
+method new_expression($/) {
+    ## get the invocant of 'new'
+    my $past := $( $<member_expression> );
+
+    ## for each occurrence of 'new', create a 'call' op, giving the current
+    ## past as argument. This is done 'inside out', so the last 'new' is invoked
+    ## first, so to say.
+    for $<sym> {
+        $past := PAST::Op.new( $past, :name('new'), :pasttype('callmethod'), :node($/) );
+    }
+    make $past;
+}
+
+method identifier($/) {
+    our $?BLOCK;
+    my $name := ~$/;
+    my $scope;
+    ## try to find the current identifier in the current block's symbol table;
+    ## if present, the scope is lexical, otherwise it's 'package'.
+    if $?BLOCK.symbol( $name ) {
+        $scope := 'lexical';
+    }
+    else {
+        $scope := 'package';
+    }
+    make PAST::Var.new( :name($name),
+                        :scope($scope),
+                        :node($/)
+                        ,:viviself('Undef') );
+}
+
+method literal($/, $key) {
+    make $( $/{$key} );
+}
+
+method builtin_literal($/, $key) {
+    make $( $/{$key} );
+}
+
+method true($/) {
+    # XXX change this into type a ECMAScript type, 'Boolean' or whatever
+    make PAST::Var.new( :name(~$/), :namespace('JSBoolean'), :scope('package'), :node($/) );
+}
+
+method false($/) {
+    # XXX change this into type 'Boolean' or whatever
+    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('null'), :namespace('JSNull'), :scope('package'), :node($/) );
+}
+
+method object_literal($/) {
+    my $past := PAST::Stmts.new( :node($/) );
+
+    my $type := PAST::Var.new( :name('JSObject'), :scope('package'), :node($/) );
+    my $objvar := PAST::Var.new(:scope('register'), :name('obj'));
+    $past.push(
+        PAST::Op.new(:pasttype('bind'),
+          PAST::Var.new(:scope('register'), :name('obj'), :isdecl(1)),
+          PAST::Op.new( :pasttype('callmethod'), :name("new"), :node($/), $type),
+          :node($/)));
+
+    for $<property> {
+      $($_).unshift($objvar);
+      $past.push( $($_) );
+    }
+    $past.push($objvar);
+    make $past;
+}
+
+method property($/) {
+    my $key  := $( $<property_name> );
+    my $val  := $( $<assignment_expression> );
+    my $past := PAST::Op.new( :inline('    %0[%1] = %2'), $key, $val, :node($/) );
+    make $past;
+}
+
+
+method property_name($/, $key) {
+    ## XXX
+    my $propname := $( $/{$key} );
+    #my $past := PAST::Op.new( :inline('    $S0 = %0'), :node($/) );
+    #$past.push($propname);
+    #make $past;
+    make $propname;
+}
+
+method array_literal($/) {
+    my $past := PAST::Stmts.new( :node($/) );
+
+    my $type := PAST::Var.new( :name('Array'), :scope('package'), :node($/) );
+    my $objvar := PAST::Var.new(:scope('register'), :name('obj'));
+    $past.push(
+        PAST::Op.new(:pasttype('bind'),
+          PAST::Var.new(:scope('register'), :name('obj'), :isdecl(1)),
+          PAST::Op.new( :pasttype('callmethod'), :name("new"), :node($/), $type),
+          :node($/)));
+    my $i := 0;
+    for $<assignment_expression> {
+      $past.push(
+          PAST::Op.new( :inline('    %0[%1] = %2'), $objvar, $i, $($_), :node($/) ));
+      $i := $i + 1;
+    }
+    $past.push($objvar);
+    make $past;
+}
+
+method element_list($/) {
+    print("el\n");
+    my $past := PAST::Stmts.new( :node($/) );
+    for $<assignment_expression> {
+      _dumper($_);
+    }
+    for $<elision> {
+      _dumper($_);
+    }
+    #for $/.list() {
+    #  _dumper($_);
+      #for $_.list() {
+      #  $past.push( $($_) );
+      #}
+    #}
+    make $past;
+}
+
+method elision($/) {
+    my $past := PAST::Stmts.new( :node($/) );
+    my $undef := PAST::Var.new( :name('undef'), :namespace('JSUndefined'), :scope('package'), :node($/) );
+
+    for $<comma> {
+      $past.push(PAST::Op.new( :pasttype('callmethod'), :name('append'), $undef, :node($/) ));
+    }
+    make $past;
+}
+
+method str_literal($/) {
+    make PAST::Val.new( :value( ~$<string_literal> ), :node($/) );
+}
+
+method floating_point_number($/) {
+    make PAST::Val.new( :value( ~$/ ), :returns('Float'), :node( $/ ) );
+}
+
+method numeric_literal($/,$key) {
+    make $( $/{$key} );
+}
+
+method integer_number($/) {
+    make PAST::Val.new( :value( ~$/ ), :returns('Integer'), :node( $/ ) );
+}
+
+method hex_integer_literal($/) {
+    make PAST::Val.new( :value( ~$/ ), :returns('Integer'), :node( $/ ) );
+}
+
+method decimal_literal($/, $key) {
+    make $( $/{$key} );
+}
+
+#method logical_or_expression($/, $key) {
+method assignment_expression($/, $key) {
+    ## Handle the operator table
+    ##
+    if ($key eq 'end') {
+        make $($<expr>);
+    }
+    else {
+        my $past := PAST::Op.new( :name($<type>),
+                                  :pasttype($<top><pasttype>),
+                                  :pirop($<top><pirop>),
+                                  :lvalue($<top><lvalue>),
+                                  :node($/)
+                                );
+        for @($/) {
+            $past.push( $($_) );
+        }
+        make $past;
+    }
+}
+

Added: ecmascript/trunk/src/parser/grammar.pg
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/src/parser/grammar.pg	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,675 @@
+# Copyright (C) 2008, Parrot Foundation.
+# $Id: grammar.pg 36833 2009-02-17 20:09:26Z allison $
+
+## ECMAscript grammar, based on the grammar as defined in the
+## reference manual.
+##
+## See "ECMAScript Language Specification"
+## Standard ECMA-262, 3rd edition, December 1999
+
+grammar JS::Grammar is PCT::Grammar;
+
+token TOP {
+    {*}                            #= open
+    <source_element>*
+    [ $ || <panic: Syntax error> ]
+    {*}                            #= close
+}
+
+rule source_element {
+    | <function_declaration> {*}   #= function_declaration
+    | <statement> {*}              #= statement
+}
+
+##
+## functions
+##
+
+rule function_declaration {
+    'function' <identifier> <function_common>
+    {*}
+}
+
+rule function_expression {
+    'function' <identifier>? <function_common>
+    {*}
+}
+
+rule function_common {
+    '(' <formal_parameter_list> ')'
+    <block>
+    {*}
+}
+
+rule formal_parameter_list {
+    [ <identifier> [',' <identifier>]* ]?
+    {*}
+}
+
+##
+## statements
+##
+
+rule statement {
+##tewk  added function_expression, don't know if it should go here though
+    | <function_expression> {*}   #= function_expression
+    | <expression_statement> {*}  #= expression_statement
+    | <block> {*}                 #= block
+    | <variable_statement> {*}    #= variable_statement
+    | <empty_statement> {*}       #= empty_statement
+    | <if_statement> {*}          #= if_statement
+    | <while_statement> {*}       #= while_statement
+    | <do_while_statement> {*}    #= do_while_statement
+    | <for1_statement> {*}        #= for1_statement
+    | <for2_statement> {*}        #= for2_statement
+    | <for3_statement> {*}        #= for3_statement
+    | <for4_statement> {*}        #= for4_statement
+    | <continue_statement> {*}    #= continue_statement
+    | <break_statement> {*}       #= break_statement
+    | <return_statement> {*}      #= return_statement
+    #| <with_statement> {*}        #= with_statement
+    | <labelled_statement> {*}    #= labelled_statement
+    #| <switch_statement> {*}      #= switch_statement
+    | <throw_statement> {*}       #= throw_statement
+    | <try_statement> {*}         #= try_statement
+}
+
+
+rule statements {
+    <statement>*
+    {*}
+}
+
+rule block {
+    '{' <statements> '}'
+    {*}
+}
+
+rule if_statement {
+    'if' '(' <expression> ')' <statement> ['else' $<else>=<statement>]?
+    {*}
+}
+
+rule do_while_statement {
+    'do' <statement> 'while' '(' <expression> ')' ';'
+    {*}
+}
+
+rule while_statement {
+    'while' '(' <expression> ')' <statement>
+    {*}
+}
+
+rule for1_statement {
+    'for' '(' [$<init>=<expression>]?
+    ';' [$<cond>=<expression>]?
+    ';' [$<step>=<expression>]? ')'
+    <statement>
+    {*}
+}
+
+rule for2_statement {
+    'for' '(' 'var' <variable_declaration> 'in' <expression> ')'
+    <statement>
+    {*}
+}
+
+rule for3_statement {
+    'for' '(' <lhs_expression> 'in' <expression> ')'
+    <statement>
+    {*}
+}
+
+rule for4_statement {
+    'for' '(' 'var' $<init>=<variable_declaration_list>
+    ';' [$<cond>=<expression>]?
+    ';' [$<step>=<expression>]? ')'
+    <statement>
+    {*}
+}
+
+rule continue_statement {
+    'continue' [\N <identifier>]? ';'
+    {*}
+}
+
+rule break_statement {
+    'break' [\N <identifier>]? ';'
+    {*}
+}
+
+rule labelled_statement {
+    <identifier> ':' <statement>
+    {*}
+}
+
+rule try_statement {
+    'try' <block>
+    [
+    | <catch> <finally>
+    | <finally>
+    | <catch>
+    ]
+    {*}
+}
+
+rule catch {
+    'catch' '(' <identifier> ')' <block>
+    {*}
+}
+
+rule finally {
+    'finally' <block>
+    {*}
+}
+
+token throw_statement {
+    'throw' \N <expression> ';'
+    {*}
+}
+
+rule variable_statement {
+    'var' <variable_declaration_list> ';'
+    {*}
+}
+
+rule variable_declaration_list {
+    <variable_declaration> [',' <variable_declaration>]*
+    {*}
+}
+
+rule variable_declaration {
+    <identifier> ['=' <assignment_expression>]?
+    {*}
+}
+
+rule empty_statement {
+    ';' {*}
+}
+
+rule expression_statement {
+    ##<!['{'|'function']> ## is this necessary? isn't this fixed automatically by PGE?
+    #<!before \w>
+    #<!['{'|'function']>
+    <expression> ';'
+    {*}
+}
+
+token return_statement {
+    'return' [\N <expression>]?  ';'
+    {*}
+}
+
+rule switch_statement {
+    'switch' '(' <expression> ')' <case_block>
+    {*}
+}
+
+rule case_block {
+    '{'
+    <case_clause>*
+    [ <default_clause>
+      <case_clause>*
+    ]?
+    '}'
+}
+
+rule case_clause {
+    'case' <expression> ':' <statements>
+    {*}
+}
+
+rule default_clause {
+    'default' ':' <statements>
+    {*}
+}
+
+rule with_statement {
+    'with' '(' <expression> ')' <statement>
+    {*}
+}
+
+
+##
+## expressions
+##
+
+
+
+rule arguments {
+    '(' [ <assignment_expression> [',' <assignment_expression>]* ]? ')'
+    {*}
+}
+
+rule primary_expression {
+    | <this> {*}                #= this
+    | <literal> {*}             #= literal
+    | <array_literal> {*}       #= array_literal
+    | <identifier> {*}          #= identifier
+    | <object_literal> {*}      #= object_literal
+    | '(' <expression> ')' {*}  #= expression
+    | <regular_expression_literal> {*} #= regular_expression_literal
+}
+
+#RegularExpressionLiteral :: See section 7.8.5
+#/ RegularExpressionBody / RegularExpressionFlags
+token regular_expression_literal {
+  '/' <regular_expression_body> '/' <regular_expression_flags>? {*}
+}
+#RegularExpressionBody :: See section 7.8.5
+#RegularExpressionFirstChar RegularExpressionChars
+token regular_expression_body {
+  <regular_expression_first_char> <regular_expression_char>*
+}
+
+#RegularExpressionChars :: See section 7.8.5
+#[empty]
+#RegularExpressionChars RegularExpressionChar
+
+#RegularExpressionFirstChar :: See section 7.8.5
+#NonTerminator but not * or \ or /
+#BackslashSequence
+token regular_expression_first_char {
+  | <-[\n*\\/]>
+  | '\\' \N
+}
+
+#RegularExpressionChar :: See section 7.8.5
+#NonTerminator but not \ or /
+#BackslashSequence
+token regular_expression_char {
+  | <-[\n\\/]>
+  | '\\' \N
+}
+
+#BackslashSequence :: See section 7.8.5
+#\ NonTerminator
+#token backslash_sequence {
+#  '\\' \N
+#}
+#
+#token NonTerminator :: See section 7.8.5
+#SourceCharacter but not LineTerminator
+#token non_terminator {
+#  \N
+#}
+
+#RegularExpressionFlags :: See section 7.8.5
+#[empty]
+#RegularExpressionFlags IdentifierPart
+token regular_expression_flags {
+  <identifier_part>+
+}
+
+token this { 'this' {*} }
+
+rule array_literal {
+##    '[' <elision>? <element_list>? [',' <elision>]?  ']'
+    '[' <assignment_expression> [',' <assignment_expression>]* ']'
+    {*}
+}
+
+rule element_list {
+    <elision>? <assignment_expression> [',' <elision>? <assignment_expression>]*
+    {*}
+}
+
+rule elision {
+    [$<comma>=',']+ {*}
+}
+
+token identifier {
+    <!reserved_word>
+    <alpha> [<alpha>|<digit>|_]*
+    {*}
+}
+
+token <identifier_part> {
+    [<alpha>|<digit>|_]
+}
+
+token literal {
+    | <str_literal> {*}            #= str_literal
+    | <numeric_literal> {*}        #= numeric_literal
+    | <builtin_literal> {*}        #= builtin_literal
+}
+
+
+token builtin_literal {
+    | <true> {*}   #= true
+    | <false> {*}  #= false
+    | <null> {*}   #= null
+}
+
+token true { 'true' {*} }
+token false { 'false' {*} }
+token null { 'null' {*} }
+
+rule object_literal {
+    '{' [ <property> [',' <property> ]* [',']? ]?  '}'
+    {*}
+}
+
+rule property {
+    <property_name> ':' <assignment_expression>
+    {*}
+}
+
+token property_name {
+    | <identifier> {*}       #= identifier
+    | <str_literal> {*}      #= str_literal
+    | <numeric_literal> {*}  #= numeric_literal
+}
+
+token numeric_literal {
+    | <hex_integer_literal> {*}    #= hex_integer_literal
+    | <decimal_literal> {*}        #= decimal_literal
+}
+
+token hex_integer_literal {
+    0<[xX]><hex_digits>+ {*}
+}
+
+token hex_digits { <[0..9 a..f A..F]> }
+
+token decimal_literal {
+    | <floating_point_number> {*}  #= floating_point_number
+    | <integer_number> {*}         #= integer_number
+}
+
+token floating_point_number {
+    [
+    | <decimal_integer_literal> '.' <digit>* <exponent_part>?
+    | '.' <digit>+ <exponent_part>?
+    ]
+    {*}
+}
+
+token integer_number {
+    <decimal_integer_literal> <exponent_part>?
+    {*}
+}
+
+token decimal_integer_literal {
+    0 | <[1..9]> <digit>*
+}
+
+token exponent_part { <[eE]> <[+\-]> <digit>+ }
+
+token str_literal {
+    [
+    | '"' <string_literal: '"'> '"'
+    | \' <string_literal: '\''> \'
+    ]
+    {*}
+}
+
+
+token keyword {
+    [ break  | case     | catch    | continue | default  | delete
+    | do     | else     | finally  | for      | function | if
+    | in     | instance | new      | return   | switch   | this
+    | throw  | try      | typeof   | var      | void     | while
+    | with
+    ] >>
+}
+
+token future_reserved_word {
+    [ abstract | enum       | int       | short
+    | boolean  | export     | interface | static
+    | byte     | extends    | long      | super
+    | char     | final      | native    | synchronized
+    | class    | float      | package   | throws
+    | const    | goto       | private   | transient
+    | debugger | implements | protected | volatile
+    ] >>
+}
+
+token reserved_word {
+    <keyword> | <future_reserved_word>
+}
+
+token singlelinecomment { '//' \N* }    # end of line comment like Unix shell and C++
+
+token multilinecomment  { '/*' .*?  '*/' }         # C-like multiline comment
+
+token ws_all {
+    | \h
+    | \v
+    | <singlelinecomment>
+    | <multilinecomment>
+}
+
+# whitespace rule used implicity by rules
+token ws {
+  | <?{{  $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
+#token ws {
+#    | <.whitespace>
+#    | <.newline>
+#    | <.comment>
+#}
+
+#token whitespace {
+#    | <[\t\v\f\ ]>
+#    | \nbsp
+#    | \usp #unicode sp
+#}
+
+#token newline {
+#    | \r?\n
+#    | \LS
+#    | \PS
+#}
+
+#token comment {
+#    <.singlelinecomment>
+#    <.multilinecomment>
+#}
+
+
+## comments
+
+#token multilinecomment {
+#    '/*' .*? '*/'
+#}
+
+#token singlelinecomment {
+#    '//' \N* \n
+#}
+
+rule expression {
+    <assignment_expression> [',' <assignment_expression>]*
+    {*}
+}
+
+#rule assignment_expression {
+#   [<lhs_expression> <assignop>]* <conditional_expression>
+#    {*}
+#}
+
+#token assignop {
+#    $<op>=['='|'*='|'/='|'%='|'+='|'-='|'<<='|'>>='|'>>>='|'&='|'^='|'|=']
+#}
+
+#rule conditional_expression {
+#    <logical_or_expression>
+#    ['?' $<then>=<assignment_expression>
+#     ':' $<else>=<assignment_expression>]?
+#    {*}
+#}
+
+rule 'assignment_expression' is optable { ... }
+
+proto 'infix:=' is precedence('1') is pasttype('copy') is lvalue(1)     { ... }
+
+proto 'infix:+=' is equiv('infix:=') { ... } 
+proto 'infix:-=' is equiv('infix:=') { ... } 
+proto 'infix:/=' is equiv('infix:=') is pirop('div')        { ... } 
+proto 'infix:*=' is equiv('infix:=') is pirop('mul')        { ... } 
+proto 'infix:%=' is equiv('infix:=') is pirop('mul')        { ... } 
+proto 'infix:|=' is equiv('infix:=')    { ... } 
+proto 'infix:&=' is equiv('infix:=')    { ... } 
+proto 'infix:~=' is equiv('infix:=')    { ... } 
+proto infix:«>>=» is equiv('infix:=') is pirop('rsh')       { ... } 
+proto infix:«<<=» is equiv('infix:=') is pirop('lsh')       { ... } 
+proto infix:«>>>=» is equiv('infix:=') is pirop('rsh')       { ... } 
+proto 'ternary:? :' is tighter('infix:=') is pirop('if')      { ... } 
+
+proto 'infix:||'  is tighter('ternary:? :') is pasttype('unless') { ... }
+
+proto 'infix:&&'  is tighter('infix:||') is pasttype('if') { ... }
+
+proto 'infix:|'   is tighter('infix:&&') { ... }
+
+proto 'infix:^'   is tighter('infix:|')  { ... }
+
+proto 'infix:&'   is tighter('infix:^')  { ... }
+
+proto 'infix:!='  is tighter('infix:&')  { ... }
+proto 'infix:=='  is equiv('infix:!=')   { ... }
+proto 'infix:===' is equiv('infix:!=')   { ... }
+proto 'infix:!==' is equiv('infix:!=')   { ... }
+
+proto infix:«<»   is tighter('infix:!=') { ... }
+proto infix:«>»   is equiv(infix:«<»)    { ... }
+proto infix:«<=»  is equiv(infix:«<»)    { ... }
+proto infix:«>=»  is equiv(infix:«<»)    { ... }
+proto 'infix:instanceof' is equiv(infix:«<») { ... }
+proto 'infix:in'  is equiv(infix:«<»)    { ... }
+
+proto infix:«<<»  is tighter(infix:«<»)  { ... }
+proto infix:«>>»  is equiv(infix:«<<»)   { ... }
+proto infix:«>>>» is equiv(infix:«<<»)   { ... }
+
+proto 'infix:+' is tighter(infix:«<<») is pirop('add') { ... }
+proto 'infix:-' is equiv('infix:+')    is pirop('sub') { ... }
+
+proto 'infix:*' is tighter('infix:+')  is pirop('mul') { ... }
+proto 'infix:/' is equiv('infix:*')    is pirop('div') { ... }
+proto 'infix:%' is equiv('infix:*')    is pirop('mod') { ... }
+
+
+rule unary_expression {
+    <unop>* <postfix_expression>
+    {*}
+}
+
+rule unop { $<op>=['delete'|'void'|'typeof'|'++'|'--'|'+'|'-'|'~'|'!'] {*} }
+
+
+proto term: is tighter(infix:<||>) is parsed(&unary_expression) { ... }
+
+rule postfix_expression {
+    # how to handle the requirement of NO linebreak? \N doesn't seem to work.
+    <lhs_expression> [ $<postfixop>=['++'|'--'] ]?
+    {*}
+}
+
+rule lhs_expression {
+    | <call_expression> {*} #= call_expression
+    | <new_expression> {*}  #= new_expression
+}
+
+rule new_expression {
+    [$<sym>='new']* <member_expression> <arguments>?
+    {*}
+}
+
+rule member_expression {
+    <member_prefix> <member_suffix>* {*}
+}
+
+rule member_prefix {
+    | <primary_expression> {*}      #= primary_expression
+    | <function_expression> {*}     #= function_expression
+}
+
+rule member_suffix {
+    | '[' <expression> ']' {*} #= expression
+    | <identifier_field> {*}   #= identifier_field
+}
+
+rule identifier_field {
+    '.' <identifier> {*}
+}
+
+rule call_expression {
+    <member_expression> <arguments> <post_call_expr>* {*}
+}
+
+rule post_call_expr {
+    | <arguments>     {*}   #= arguments
+    | <member_suffix> {*}   #= member_suffix
+}
+
+
+## Grammar rules converted directly from the ECMA-script reference manual, 3rd edition.
+## This makes converting the whole thing to an optable easier.
+##
+## These rules are handled by the operator table (bottom-up parsing method).
+##
+#
+#rule logical_or_expression {
+#    <logical_and_expression> ['||' <logical_and_expression>]*
+#}
+#
+#rule logical_and_expression {
+#    <bitwise_or_expression> ['&&' <bitwise_or_expression>]*
+#}
+#
+#rule bitwise_or_expression {
+#    <bitwise_xor_expression> ['|' <bitwise_xor_expression>]*
+#}
+#
+#rule bitwise_xor_expression {
+#    <bitwise_and_expression> ['^' <bitwise_and_expression>]*
+#}
+#
+#rule bitwise_and_expression {
+#    <equality_expression> ['&' <equality_expression>]*
+#}
+#
+#rule equality_expression {
+#    <relational_expression> [<eqop> <relational_expression>]*
+#}
+#
+#token eqop { '==' | '!=' | '===' | '!==' }
+#
+#rule relational_expression {
+#    <shift_expression> [<relop> <shift_expression>]*
+#}
+#
+#token relop { '<' | '>' | '<=' | '>=' | 'instanceof' }
+#
+#rule shift_expression {
+#    <additive_expression> [<shiftop> <additive_expression>]*
+#}
+#
+#token shiftop { '<<' | '>>' | '>>>' }
+#
+#rule additive_expression {
+#    <multiplicative_expression> [<addop> <multiplicative_expression>]*
+#}
+#
+#token addop { '+' | '-' }
+#
+#rule multiplicative_expression {
+#    <unary_expression> [<mulop> <unary_expression>]*
+#}
+#
+#token mulop { '*' | '/' | '%' }
+#

Added: ecmascript/trunk/t/00-comments.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/00-comments.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,4 @@
+/* comment 1 */
+// comment 2
+print("1..1\n");
+print("ok 1\n");

Added: ecmascript/trunk/t/01-literals.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/01-literals.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,49 @@
+print("1..11\n");
+print("ok 1\n");
+
+try {
+    print("ok 2\n");
+}
+catch(exc) {
+    print("nok 2\n");
+}
+
+if (1) {
+    print("ok 3\n");
+}
+else {
+    throw "nok 3\n";
+}
+
+if (1) {
+    print("ok 4\n");
+}
+
+while (0) {
+    print ("nok 4\n");
+}
+
+print("ok 5\n");
+
+print("ok ");
+print(1+1+1+3);
+print("\n");
+print("ok ");
+print(10-3);
+print("\nok ");
+print(1*8);
+print("\nok ");
+print(18/2);
+print("\n");
+
+var x = 1;
+x += 9;
+print("ok ");
+print(x);
+print("\n");
+
+function foo() {
+    return "ok 11\n";
+}
+
+print(foo());

Added: ecmascript/trunk/t/02-operators.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/02-operators.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,13 @@
+// Test the relational ops
+
+print ("1..8\n");
+
+if (1 < 7) { print("ok 1\n"); } else { print("nok 1\n"); }
+if (7 < 1) { print("nok 2\n"); } else { print("ok 2\n"); }
+if (1 <= 7) { print("ok 3\n"); } else { print("nok 3\n"); }
+if (7 <= 7) { print("ok 4\n"); } else { print("nok 4\n"); }
+
+if (7 > 3) { print("ok 5\n"); } else { print("nok 5\n"); }
+if (3 > 7) { print("nok 6\n"); } else { print("ok 6\n"); }
+if (7 >= 3) { print("ok 7\n"); } else { print("nok 7\n"); }
+if (3 >= 3) { print("ok 8\n"); } else { print("nok 8\n"); }

Added: ecmascript/trunk/t/02-sanity-var.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/02-sanity-var.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,10 @@
+print("1..1\n");
+var STATUS = "STATUS: ";
+print("#");
+print(STATUS);
+print("\n");
+print("ok 1\n");
+
+/*
+ * vim: ft=javascript:
+ */

Added: ecmascript/trunk/t/harness
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/harness	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,168 @@
+#! perl
+# $Id: harness 34360 2008-12-25 22:16:50Z tewk $
+
+=head1 NAME
+
+languages/ecmascript/t/harness - A harness for JS
+
+=head1 SYNOPSIS
+
+  cd languages && perl ecmascript/t/harness --files --master
+
+  cd languages/ecmascript && perl t/harness 
+
+  cd languages/ecmascript && perl t/harness --verbose t/hello.t 
+
+=head1 DESCRIPTION
+
+If I'm called with a single
+argument of "--files", I just return a list of files to process.
+This list is one per line, and is relative to the languages dir.
+
+If I'm called with no args, I run the complete suite.
+
+Otherwise I run the tests that were passed on the command line.
+
+=cut
+
+# pragmata
+use strict;
+use warnings;
+use FindBin ();
+use lib "$FindBin::Bin/../../../lib", "$FindBin::Bin/../lib";
+
+use Cwd                     ();
+use File::Spec              ();
+use TAP::Harness            3.12;     # support closures for the 'exec' option
+use TAP::Harness::Archive   0.12; 
+use Parrot::Config          qw( %PConfig );
+use Getopt::Long;
+use Parrot::Harness::Smoke;
+use Parrot::Test;
+
+my ( $files_flag, $master_flag, $send_to_smolder_flag, $archive_flag, $verbose_flag );
+my ( $js_flag, $pjs_flag);
+GetOptions(
+    'files'           => \$files_flag,
+    'master'          => \$master_flag,          # unused, but passed by languages/t/harness
+    'send-to-smolder' => \$send_to_smolder_flag,
+    'archive'         => \$archive_flag,
+    'verbose'         => \$verbose_flag,
+    'with-pjs'        => \$pjs_flag,
+    'with-js'         => \$js_flag,
+);
+
+my $hll = 'ecmascript';
+my $verbosity = $verbose_flag ? 1 : $ENV{HARNESS_VERBOSE};
+$verbosity ||= 0;
+
+if ( $files_flag ) {
+    # Only the Makefile in 'parrot/languages' uses --files for unified testing
+    my $dir = File::Spec->catfile( $hll, 't' );
+    # unified testing can't handle test scripts written in JS
+    my @files = grep { ! m!in_php|pmc|embed! } glob( File::Spec->catfile( $dir, '*/*.t' ) );
+    print join( "\n", @files );
+    print "\n" if scalar(@files);
+}
+else { 
+    my $path_to_parrot = Parrot::Test::path_to_parrot();
+    my @cmd = ( "$path_to_parrot/parrot$PConfig{exe}", "$path_to_parrot/languages/ecmascript/js.pbc" );
+    $ENV{PARROT_PIPP_TEST_MODULE} = 'Parrot::Test::JS::PJS';
+
+    if ( $js_flag ) { 
+         $ENV{PARROT_PIPP_TEST_MODULE} = 'Parrot::Test::JS::SpiderMonkey';
+         @cmd = qw{ js } ;
+    }
+    elsif ( $pjs_flag ) {
+        $ENV{PARROT_PIPP_TEST_MODULE} = 'Parrot::Test::JS::PJS';
+    }
+
+    my @files;
+    if ( scalar(@ARGV) ) {
+        # Someone specified tests for me to run.
+        @files = grep { -f $_ } @ARGV
+    }
+    else {
+        ( undef, undef, my $current_dir ) = File::Spec->splitpath( Cwd::getcwd() );
+        if ( $current_dir eq 'languages' ) {
+            @files = glob( File::Spec->catfile( $hll, 't', '*/*.t' ) );
+        }
+        elsif ( $current_dir eq $hll ) {
+            @files = glob( File::Spec->catfile( 't', '*/*.t' ) );
+            print glob( File::Spec->catfile( 't', '*.t' ) );
+            push @files, glob( File::Spec->catfile( 't', '*.t' ) );
+        }
+        else {
+            die "Where am I?";
+        }
+    }
+
+    my $exec_sub
+        = sub {
+              my ( $harness, $test_file ) = @_;
+
+              # the directory t/embed contains only PIR test files
+              return [ "$path_to_parrot/parrot$PConfig{exe}", $test_file ] if $test_file =~ m{t/embed/.*[.]t$};
+
+              # the directory t/pmc contains only PIR test files
+              return [ "$path_to_parrot/parrot$PConfig{exe}", $test_file ] if $test_file =~ m{t/pmc/.*[.]t$};
+
+              # the directory t/in_php contains only test scripts written in JS
+              return [ @cmd, $test_file ] if $test_file =~ m{t/sanity_js/.*[.]t$};
+              if ($test_file =~ m{^t/(?:[^/])*\.t$!}) {
+                print "$test_file\n";
+                return [ @cmd, $test_file ];
+              }
+
+
+              # all other directories contain test scripts written in Perl
+              return [ $PConfig{perl}, $test_file ];
+          };  
+    if ( $archive_flag ) { 
+        my %env_data = Parrot::Harness::Smoke::collect_test_environment_data();
+       
+        my $report_file = ['js_test_run.tar.gz'];
+        my $harness = TAP::Harness::Archive->new(
+            {
+                exec             => $exec_sub,
+                verbosity        => $verbosity,
+                archive          => $report_file->[0],
+                merge            => 1,
+                extra_properties => \%env_data,
+            }
+        );
+        $harness->runtests(@files);
+
+        if ( $send_to_smolder_flag ) {
+            $env_data{report_file} = $report_file;
+            $env_data{project_id}  = 10;
+            Parrot::Harness::Smoke::send_archive_to_smolder(%env_data);
+        }
+    } else {
+       my $harness = TAP::Harness->new(
+           {
+               exec       => $exec_sub,
+               verbosity  => $verbosity,
+           }
+       );
+        $harness->runtests(@files);
+    }
+}
+
+=head1 SEE ALSO
+
+  F<languages/perl6/t/harness>
+
+=head1 AUTHOR
+
+Bernhard Schmalhofer - <Bernhard.Schmalhofer at gmx.de>
+Kevin Tew - <tewk at tewk dot com>
+
+=cut
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:

Added: ecmascript/trunk/t/js_pt/00-template.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/js_pt/00-template.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+# Copyright (C) 2008, Parrot Foundation.
+# $Id: 00-template.t 36833 2009-02-17 20:09:26Z allison $
+
+use strict;
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/../../../../lib", "$FindBin::Bin/../../lib";
+
+use Parrot::Test tests => 2;
+
+language_output_is( 'JS', <<'CODE', <<'OUT', '' );
+CODE
+OUT
+
+language_output_is( 'JS', <<'CODE', <<'OUT', '', todo => 'todoed');
+CODE
+FAILED
+OUT
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:

Added: ecmascript/trunk/t/js_pt/09-array.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/js_pt/09-array.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,24 @@
+#!/usr/bin/perl
+# Copyright (C) 2008, Parrot Foundation.
+# $Id: 09-array.t 36833 2009-02-17 20:09:26Z allison $
+
+use strict;
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/../../../../lib", "$FindBin::Bin/../../lib";
+
+use Parrot::Test tests => 1;
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'new array into var', todo => 'NOTIMPLEMENTED');
+var a = new Array();
+print(a.length);
+CODE
+0
+OUT
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:

Added: ecmascript/trunk/t/js_pt/09-array_literals.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/js_pt/09-array_literals.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,29 @@
+#!/usr/bin/perl
+# Copyright (C) 2008, Parrot Foundation.
+# $Id: 09-array_literals.t 36833 2009-02-17 20:09:26Z allison $
+
+use strict;
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/../../../../lib", "$FindBin::Bin/../../lib";
+
+use Parrot::Test tests => 2;
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'array literal of strings', todo => 'NOTIMPLEMENTED' );
+var digits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
+print(digits);
+CODE
+0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
+OUT
+language_output_is( 'JS', <<'CODE', <<'OUT', 'array literal of strings', todo => 'elision' );
+var a = [,,,,1,2,,,,,,3,4,,,,,];
+CODE
+0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
+OUT
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:

Added: ecmascript/trunk/t/js_pt/10-version.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/js_pt/10-version.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,41 @@
+#!/usr/bin/perl
+# Copyright (C) 2008, Parrot Foundation.
+# $Id: 10-version.t 36833 2009-02-17 20:09:26Z allison $
+
+use strict;
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/../../../../lib", "$FindBin::Bin/../../lib";
+
+use Parrot::Test tests => 2;
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'version builtin' );
+function a() {
+}
+print(typeof version);
+print(version(150));
+print(version);
+print((typeof version) == (typeof a));
+CODE
+function
+0
+version
+true
+OUT
+
+todo: {
+language_output_is( 'JS', <<'CODE', <<'OUT', 'version global', todo => 'need to wrap parrot subs');
+print(version);
+CODE
+function version() {
+    [native code]
+}
+OUT
+}
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:

Added: ecmascript/trunk/t/js_pt/11-global_object.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/js_pt/11-global_object.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+# Copyright (C) 2008, Parrot Foundation.
+# $Id: 11-global_object.t 36833 2009-02-17 20:09:26Z allison $
+
+use strict;
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/../../../../lib", "$FindBin::Bin/../../lib";
+
+use Parrot::Test tests => 1;
+
+language_output_is( 'JS', <<'CODE', <<'OUT', '', todo => 'NOTIMPLEMENTED' );
+print(this);
+CODE
+[object global]
+OUT
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:

Added: ecmascript/trunk/t/js_pt/12-regex.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/js_pt/12-regex.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+# Copyright (C) 2008, Parrot Foundation.
+# $Id: 12-regex.t 36833 2009-02-17 20:09:26Z allison $
+
+use strict;
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/../../../../lib", "$FindBin::Bin/../../lib";
+
+use Parrot::Test tests => 1;
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'print a simple regex', todo => 'NOTIMPLEMENTED');
+print( /a/ );
+CODE
+/a/
+OUT
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:

Added: ecmascript/trunk/t/sanity_pt/00-literals.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/sanity_pt/00-literals.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,48 @@
+#!/usr/bin/perl
+# Copyright (C) 2008, Parrot Foundation.
+# $Id: 00-literals.t 36833 2009-02-17 20:09:26Z allison $
+
+use strict;
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/../../../../lib", "$FindBin::Bin/../../lib";
+
+use Parrot::Test tests => 3;
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'number literals' );
+print(1);
+print(-1);
+print(100);
+print(-100);
+print(0);
+CODE
+1
+-1
+100
+-100
+0
+OUT
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'string literals' );
+print("Hello");
+print("Bye");
+CODE
+Hello
+Bye
+OUT
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'float literals' );
+print(1.0);
+print(1.1);
+CODE
+1
+1.1
+OUT
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:
+

Added: ecmascript/trunk/t/sanity_pt/01-vars.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/sanity_pt/01-vars.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,39 @@
+#!/usr/bin/perl
+# Copyright (C) 2008, Parrot Foundation.
+# $Id: 01-vars.t 36833 2009-02-17 20:09:26Z allison $
+
+use strict;
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/../../../../lib", "$FindBin::Bin/../../lib";
+
+use Parrot::Test tests => 3;
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'number var' );
+var a = 1;
+print(a);
+CODE
+1
+OUT
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'string var' );
+var b = "Hello";
+print(b);
+CODE
+Hello
+OUT
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'printing booleans' );
+var c = 1.1;
+print(c);
+CODE
+1.1
+OUT
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:
+

Added: ecmascript/trunk/t/sanity_pt/03-boolean.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/sanity_pt/03-boolean.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,46 @@
+#!/usr/bin/perl
+# Copyright (C) 2008, Parrot Foundation.
+# $Id: 03-boolean.t 36833 2009-02-17 20:09:26Z allison $
+
+use strict;
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/../../../../lib", "$FindBin::Bin/../../lib";
+
+use Parrot::Test tests => 3;
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'basic booleans' );
+print(true == true);
+print(false == false);
+print(true == false);
+print(false == true);
+CODE
+true
+true
+false
+false
+OUT
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'basic booleans', todo => 'get_integer on JSBoolean leads to eternal recursion' );
+print(true + 1);
+print(false + 1);
+CODE
+2
+1
+OUT
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'printing booleans' );
+print(true);
+print(false);
+CODE
+true
+false
+OUT
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:
+

Added: ecmascript/trunk/t/sanity_pt/05-objects.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ ecmascript/trunk/t/sanity_pt/05-objects.t	Wed Mar 11 02:15:26 2009	(r33)
@@ -0,0 +1,48 @@
+#!/usr/bin/perl
+# Copyright (C) 2008, Parrot Foundation.
+# $Id: 05-objects.t 36833 2009-02-17 20:09:26Z allison $
+
+use strict;
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/../../../../lib", "$FindBin::Bin/../../lib";
+
+use Parrot::Test tests => 4;
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'empty object', todo => 'toString broken' );
+var a = {};
+print(a);
+CODE
+[object Object]
+OUT
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'object with primitive fields', todo => 'fields broken' );
+var a = { 0: 1, 1: 2, };
+print(a);
+CODE
+[object Object]
+OUT
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'nested objects', todo => 'fields broken' );
+var a = { a: { aa: "duh" },
+          b: { bb: "huh" },
+          c: { cc: "wuh" },
+          };
+print(a);
+CODE
+[object Object]
+OUT
+
+language_output_is( 'JS', <<'CODE', <<'OUT', 'objects with array members', todo => 'NOTIMPLEMENTED');
+var deriv = {X: [], Y: [] };
+CODE
+OUT
+
+
+# Local Variables:
+#   mode: cperl
+#   cperl-indent-level: 4
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:
+


More information about the parrot-commits mailing list