[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