Skip to content
Browse files

Initial version of perk, adapted from http://svn.chrisdolan.net/langu…

…ages/java/

It just parses (slowly but accurately) and generates no PAST.


git-svn-id: https://squawk.googlecode.com/svn/trunk/perk@3 4fec983b-2331-0410-8aff-915880dc51bf
  • Loading branch information...
0 parents commit 56805f4a6af9c1229f9cbe479c2984d0a3a1564d cjdolan committed
Showing with 1,404 additions and 0 deletions.
  1. +131 −0 Makefile
  2. +12 −0 README
  3. +127 −0 config/makefiles/root.in
  4. +85 −0 parse_tests/test.pl
  5. +66 −0 perk.pir
  6. +31 −0 src/builtins/say.pir
  7. +100 −0 src/parser/actions.pm
  8. +13 −0 src/parser/grammar-oper.pg
  9. +819 −0 src/parser/grammar.pg
  10. +7 −0 t/00-sanity.t
  11. +13 −0 t/harness
131 Makefile
@@ -0,0 +1,131 @@
+# ex: set ro ft=make:
+# DO NOT EDIT THIS FILE
+# Generated by Parrot::Configure::Compiler from languages/perk/config/makefiles/root.in
+
+## $Id$
+
+## arguments we want to run parrot with
+PARROT_ARGS =
+
+## configuration settings
+BUILD_DIR = /Users/chris/Work/parrot
+LOAD_EXT = .bundle
+O = .o
+
+## Setup some commands
+LN_S = /bin/ln -s
+PERL = perl
+RM_RF = $(PERL) -MExtUtils::Command -e rm_rf
+CP = $(PERL) -MExtUtils::Command -e cp
+PARROT = ../../parrot
+CAT = $(PERL) -MExtUtils::Command -e cat
+BUILD_DYNPMC = $(PERL) $(BUILD_DIR)/tools/build/dynpmc.pl
+RECONFIGURE = $(PERL) $(BUILD_DIR)/tools/dev/reconfigure.pl
+
+# MACOSX_DEPLOYMENT_TARGET must be defined for OS X compilation/linking
+export MACOSX_DEPLOYMENT_TARGET := 10.4
+
+## 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
+
+PMC_DIR = src/pmc
+
+all: perk.pbc
+
+PERK_GROUP = $(PMC_DIR)/perk_group$(LOAD_EXT)
+
+SOURCES = perk.pir \
+ src/gen_grammar.pir \
+ src/gen_actions.pir \
+ src/gen_builtins.pir \
+# $(PERK_GROUP)
+
+BUILTINS_PIR = \
+ src/builtins/say.pir \
+
+# PMCS = perk
+# PMC_SOURCES = $(PMC_DIR)/perk.pmc
+
+# the default target
+perk.pbc: $(PARROT) $(SOURCES)
+ $(PARROT) $(PARROT_ARGS) -o perk.pbc perk.pir
+
+src/gen_grammar.pir: $(PERL6GRAMMAR) src/parser/grammar.pg src/parser/grammar-oper.pg
+ $(PARROT) $(PARROT_ARGS) $(PERL6GRAMMAR) \
+ --output=src/gen_grammar.pir \
+ src/parser/grammar.pg \
+ src/parser/grammar-oper.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
+
+src/gen_builtins.pir: $(BUILTINS_PIR)
+ $(CAT) $(BUILTINS_PIR) >src/gen_builtins.pir
+
+$(PERK_GROUP): $(PARROT) $(PMC_SOURCES)
+ cd $(PMC_DIR) && $(BUILD_DYNPMC) generate $(PMCS)
+ cd $(PMC_DIR) && $(BUILD_DYNPMC) compile $(PMCS)
+ cd $(PMC_DIR) && $(BUILD_DYNPMC) linklibs $(PMCS)
+ cd $(PMC_DIR) && $(BUILD_DYNPMC) copy --destination=$(PARROT_DYNEXT) $(PMCS)
+
+# regenerate the Makefile
+Makefile: config/makefiles/root.in
+ cd $(BUILD_DIR) && $(RECONFIGURE) --step=gen::languages --languages=perk
+
+# 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: perk.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
+
+# this target has nothing to do
+testclean:
+
+CLEANUPS = \
+ perk.pbc \
+ src/gen_grammar.pir \
+ src/gen_actions.pir \
+ src/gen_builtins.pir \
+ $(PMC_DIR)/*.h \
+ $(PMC_DIR)/*.c \
+ $(PMC_DIR)/*.dump \
+ $(PMC_DIR)/*$(O) \
+ $(PMC_DIR)/*$(LOAD_EXT) \
+ $(PMC_DIR)/*.exp \
+ $(PMC_DIR)/*.ilk \
+ $(PMC_DIR)/*.manifest \
+ $(PMC_DIR)/*.pdb \
+ $(PMC_DIR)/*.lib \
+
+
+clean: testclean
+ $(RM_RF) $(CLEANUPS)
+
+realclean: clean
+ $(RM_RF) Makefile
+
+distclean: realclean
+
+
12 README
@@ -0,0 +1,12 @@
+This is an implementation of the Java programming language. It is not
+intended to be an implementation of the Java virtual machine, however,
+so it will not be interoperable with existing JavaVM bytecode.
+
+The parser is heavily influenced by an ANTLR grammar for Java 1.5.
+
+ http://www.antlr.org/grammar/1152141644268/Java.g
+
+From those roots, though, it's been modified to be more tightly
+coupled with Parrot and has been enhanced to support more syntax from
+the Java Language Specification, 3rd edition to parse a wider variety
+of Java sources (i.e. Java 1.6 and beyond).
127 config/makefiles/root.in
@@ -0,0 +1,127 @@
+## $Id$
+
+## 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_RF = @rm_rf@
+CP = @cp@
+PARROT = ../../parrot@exe@
+CAT = $(PERL) -MExtUtils::Command -e 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
+
+PMC_DIR = src/pmc
+
+all: perk.pbc
+
+PERK_GROUP = $(PMC_DIR)/perk_group$(LOAD_EXT)
+
+SOURCES = perk.pir \
+ src/gen_grammar.pir \
+ src/gen_actions.pir \
+ src/gen_builtins.pir \
+# $(PERK_GROUP)
+
+BUILTINS_PIR = \
+ src/builtins/say.pir \
+
+# PMCS = perk
+# PMC_SOURCES = $(PMC_DIR)/perk.pmc
+
+# the default target
+perk.pbc: $(PARROT) $(SOURCES)
+ $(PARROT) $(PARROT_ARGS) -o perk.pbc perk.pir
+
+src/gen_grammar.pir: $(PERL6GRAMMAR) src/parser/grammar.pg src/parser/grammar-oper.pg
+ $(PARROT) $(PARROT_ARGS) $(PERL6GRAMMAR) \
+ --output=src/gen_grammar.pir \
+ src/parser/grammar.pg \
+ src/parser/grammar-oper.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
+
+src/gen_builtins.pir: $(BUILTINS_PIR)
+ $(CAT) $(BUILTINS_PIR) >src/gen_builtins.pir
+
+$(PERK_GROUP): $(PARROT) $(PMC_SOURCES)
+ cd $(PMC_DIR) && $(BUILD_DYNPMC) generate $(PMCS)
+ cd $(PMC_DIR) && $(BUILD_DYNPMC) compile $(PMCS)
+ cd $(PMC_DIR) && $(BUILD_DYNPMC) linklibs $(PMCS)
+ cd $(PMC_DIR) && $(BUILD_DYNPMC) copy --destination=$(PARROT_DYNEXT) $(PMCS)
+
+# regenerate the Makefile
+Makefile: config/makefiles/root.in
+ cd $(BUILD_DIR) && $(RECONFIGURE) --step=gen::languages --languages=perk
+
+# 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: perk.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
+
+# this target has nothing to do
+testclean:
+
+CLEANUPS = \
+ perk.pbc \
+ src/gen_grammar.pir \
+ src/gen_actions.pir \
+ src/gen_builtins.pir \
+ $(PMC_DIR)/*.h \
+ $(PMC_DIR)/*.c \
+ $(PMC_DIR)/*.dump \
+ $(PMC_DIR)/*$(O) \
+ $(PMC_DIR)/*$(LOAD_EXT) \
+ $(PMC_DIR)/*.exp \
+ $(PMC_DIR)/*.ilk \
+ $(PMC_DIR)/*.manifest \
+ $(PMC_DIR)/*.pdb \
+ $(PMC_DIR)/*.lib \
+
+
+clean: testclean
+ $(RM_RF) $(CLEANUPS)
+
+realclean: clean
+ $(RM_RF) Makefile
+
+distclean: realclean
+
+
85 parse_tests/test.pl
@@ -0,0 +1,85 @@
+#!/usr/bin/perl -w
+
+use strict;
+use FindBin qw($Bin);
+use File::Find;
+use File::Slurp;
+use File::Which;
+
+# If -f is specified, re-run failures even if we already recorded a failure
+my $force = @ARGV && $ARGV[0] eq '-f' && shift;
+
+my $filter = shift;
+
+## Pick a folder full of .java files to try to parse
+my $javadir = "$Bin/openjdk/jdk/src/share/classes";
+
+if (! -e $javadir) {
+ die "No OpenJDK source code found at\n" .
+ " $javadir\n" .
+ "Download and unpack code from http://openjdk.java.net/ and try again\n";
+}
+
+my $parrotexe = File::Which::which 'parrot';
+if (!$parrotexe) {
+ for my $i (1..5) {
+ my $candidate = $Bin . ('/..' x $i) . '/parrot';
+ if (-x $candidate) {
+ $parrotexe = $candidate;
+ last;
+ }
+ }
+ if (!$parrotexe) {
+ die "Can't find parrot\n";
+ }
+}
+
+my $outdir = "$Bin/testout";
+mkdir $outdir;
+mkdir "$outdir/bad";
+mkdir "$outdir/good";
+my $perkcode = "$Bin/../perk.pbc";
+find({wanted => sub {
+ return if ! m/\.java\z/;
+ return if m/-/; # can't handle invalid Java files with dashes in the file names
+ return if $filter && !m{\A$javadir/$filter};
+ #if (m{sun/nio/cs/ext/(GB18030|EUC_TW|IBM\d+|Johab|HKSCS_2001|MS\d+).java\z}xms) {
+ if (m{sun/nio/cs/ext/\w+.java\z}xms) {
+ print "SKIPPED $_\n";
+ return;
+ }
+ print "$_\n";
+ my $esc = $_;
+ $esc =~ s{\A $javadir/}{}xms;
+ $esc =~ s{/}{.}gxms;
+ $esc =~ s{\.java\z}{}xms;
+ my $goodfile = "$outdir/good/$esc";
+ my $badfile = "$outdir/bad/$esc";
+ if (-e $badfile) {
+ return if !$force && ! -z $badfile && -M $badfile < -M $perkcode;
+ unlink $badfile;
+ unlink $badfile . '.java';
+ }
+ return if -e $goodfile;
+ my $ret = system("'$parrotexe' '$perkcode' $_ > '$badfile'");
+ my $exit = $?;
+ if ( $ret == 0 ) {
+ rename($badfile, $goodfile);
+ } else {
+ print "Returned error: $ret\n";
+ if ($exit == -1) {
+ print "Failed to launch\n";
+ unlink $badfile;
+ exit -1;
+ } elsif ($exit & 127) {
+ print "died with signal ", ($exit & 127), "\n";
+ unlink $badfile;
+ exit -1;
+ } else {
+ print "exit value: ", ($exit >> 8), "\n";
+ #sleep 1;
+ write_file($badfile . '.java', scalar read_file($_));
+ }
+ }
+ return;
+}, no_chdir => 1}, $javadir);
66 perk.pir
@@ -0,0 +1,66 @@
+=head1 TITLE
+
+perk.pir - A perk compiler.
+
+=head2 Description
+
+This is the base file for the perk compiler.
+
+This file includes the parsing and grammar rules from
+the src/ directory, loads the relevant PGE libraries,
+and registers the compiler under the name 'perk'.
+
+=head2 Functions
+
+=over 4
+
+=item onload()
+
+Creates the perk compiler using a C<PCT::HLLCompiler>
+object.
+
+=cut
+
+.namespace [ 'perk';'Compiler' ]
+
+.loadlib 'perk_group'
+
+.sub 'onload' :anon :load :init
+ load_bytecode 'PCT.pbc'
+
+ $P0 = get_hll_global ['PCT'], 'HLLCompiler'
+ $P1 = $P0.'new'()
+ $P1.'language'('perk')
+ $P1.'parsegrammar'('perk::Grammar')
+ $P1.'parseactions'('perk::Grammar::Actions')
+.end
+
+=item main(args :slurpy) :main
+
+Start compilation by passing any command line C<args>
+to the perk compiler.
+
+=cut
+
+.sub 'main' :main
+ .param pmc args
+
+ $P0 = compreg 'perk'
+ $P1 = $P0.'command_line'(args)
+.end
+
+
+.include 'src/gen_builtins.pir'
+.include 'src/gen_grammar.pir'
+.include 'src/gen_actions.pir'
+
+=back
+
+=cut
+
+# Local Variables:
+# mode: pir
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
+
31 src/builtins/say.pir
@@ -0,0 +1,31 @@
+# $Id$
+
+=head1
+
+say.pir -- simple implementation of a say function
+
+=cut
+
+.namespace []
+
+.sub 'say'
+ .param pmc args :slurpy
+ .local pmc iter
+ iter = new 'Iterator', args
+ iter_loop:
+ unless iter goto iter_end
+ $P0 = shift iter
+ print $P0
+ goto iter_loop
+ iter_end:
+ print "\n"
+ .return ()
+.end
+
+
+# Local Variables:
+# mode: pir
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
+
100 src/parser/actions.pm
@@ -0,0 +1,100 @@
+# $Id$
+
+=begin comments
+
+perk::Grammar::Actions - ast transformations for perk
+
+********
+THIS INITIAL VERSION IS PURELY DEBUG CODE! There is no real implementation here yet...
+********
+
+This file contains the methods that are used by the parse grammar
+to build the PAST representation of an perk program.
+Each method below corresponds to a rule in F<src/parser/grammar.pg>,
+and is invoked at the point where C<{*}> appears in the rule,
+with the current match object as the first argument. If the
+line containing C<{*}> also has a C<#= key> comment, then the
+value of the comment is passed as the second argument to the method.
+
+=end comments
+
+class perk::Grammar::Actions;
+
+method TOP($/) {
+ say('TOP');
+ make PAST::Block.new( :pirflags(':main') );
+}
+method compilationUnit($/) {
+ say('compilationUnit');
+}
+method packageDeclaration($/) {
+ say('package');
+}
+method annotation($/) {
+ say('annot:');
+ say($<annotationName>);
+}
+method importDeclaration($/) {
+ say($/);
+}
+method fieldDeclaration($/) {
+ say('field:');
+ say($/);
+}
+method methodDeclaration($/) {
+ say('method:');
+ say($<Identifier>);
+}
+method block($/) {
+ say('block:');
+ say($/);
+}
+method expression($/) {
+ say('expression:');
+ say($/);
+}
+method parExpression($/) {
+ say('parExpression:');
+ say($/);
+}
+method blockStatement($/) {
+ say('statement:');
+ say($<statement>);
+}
+method localVariableDeclaration($/) {
+ say('local:');
+ say($/);
+}
+method normalClassDeclaration($/, $key) {
+ if ($key eq 'start') {
+ say('class:');
+ say($<Identifier>);
+ }
+}
+method arrayCreatorRest($/) {
+ say('arrayCreatorRest, expr:');
+ say($<expression>);
+}
+
+method primary($/) {
+ say('primary, this:');
+ say($/);
+}
+
+method switchLabel($/, $key) {
+ say('switchLabel:');
+ if ($key eq 'normal') {
+ say($<constantExpression>);
+ } elsif ($key eq 'enum') {
+ say($<enumConstantName>);
+ } elsif ($key eq 'default') {
+ say('default');
+ }
+}
+
+# Local Variables:
+# mode: cperl
+# cperl-indent-level: 4
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:
13 src/parser/grammar-oper.pg
@@ -0,0 +1,13 @@
+# THIS FILE IS NOT YET USED...
+
+## expressions and operators
+proto 'term:' is precedence('=') is parsed(&term) { ... }
+
+## multiplicative operators
+proto infix:<*> is looser(term:) is pirop('mul') { ... }
+proto infix:</> is equiv(infix:<*>) is pirop('div') { ... }
+
+## additive operators
+proto infix:<+> is looser(infix:<*>) is pirop('add') { ... }
+proto infix:<-> is equiv(infix:<+>) is pirop('sub') { ... }
+
819 src/parser/grammar.pg
@@ -0,0 +1,819 @@
+# This Parrot implementation of a Java parser is adapted from
+# http://www.antlr.org/grammar/1152141644268/Java.g
+# Initial implementation by Chris Dolan.
+
+# The following license comes from that ANTLR grammar:
+
+# [The "BSD licence"]
+# Copyright (c) 2007-2008 Terence Parr
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+=begin overview
+
+This is the grammar for perk written as a sequence of Perl 6 rules.
+
+=end overview
+
+grammar perk::Grammar is PCT::Grammar;
+
+rule TOP {
+ <compilationUnit>
+ [ $ || <panic: 'Syntax error'> ]
+ {*}
+}
+
+token ws {
+ | <!ww> <ws_all>+
+ | <ws_all>*
+}
+
+token ws_all {
+ | \h+
+ | \v+
+ | '//' \N*
+ | '/*' .*? '*/'
+}
+
+rule compilationUnit {
+ | <annotation>+ [
+ | <packageDeclaration> <importDeclaration>* <typeDeclaration>*
+ | <classOrInterfaceDeclaration> <typeDeclaration>*
+ ]
+ | <packageDeclaration>? <importDeclaration>* <typeDeclaration>*
+}
+
+rule packageDeclaration {
+ 'package' <qualifiedName> ';'
+}
+
+rule importDeclaration {
+ 'import' 'static'? <qualifiedName> ['.' '*']? ';' {*}
+}
+
+rule typeDeclaration {
+ | <classOrInterfaceDeclaration>
+ | ';'
+}
+
+rule classOrInterfaceDeclaration {
+ <classOrInterfaceModifiers> [ <classDeclaration> | <interfaceDeclaration> ]
+}
+
+rule classOrInterfaceModifiers {
+ <classOrInterfaceModifier>*
+}
+
+rule classOrInterfaceModifier {
+ | <annotation>
+ | 'public'<!before \w>
+ | 'protected'<!before \w>
+ | 'private'<!before \w>
+ | 'abstract'<!before \w>
+ | 'static'<!before \w>
+ | 'final'<!before \w>
+ | 'strictfp'<!before \w>
+}
+
+rule modifiers {
+ <modifier>*
+}
+
+rule classDeclaration {
+ | <normalClassDeclaration>
+ | <enumDeclaration>
+}
+
+rule normalClassDeclaration {
+ 'class' <Identifier> <typeParameters>?
+ ['extends' <type>]?
+ ['implements' <typeList>]? {*} #= start
+ <classBody>
+}
+
+rule typeParameters {
+ '<' <typeParameter> [ ',' <typeParameter> ]* '>'
+}
+rule typeParameter {
+ <Identifier> ['extends' <typeBound>]?
+}
+
+rule typeBound {
+ <type> [ '&' <type> ]*
+}
+
+rule enumDeclaration {
+ <ENUM> <Identifier> ['implements' <typeList>]?
+ <enumBody>
+}
+
+rule enumBody {
+ '{' <enumConstants>? ','? <enumBodyDeclarations>? '}'
+}
+
+rule enumConstants {
+ <enumConstant> [ ',' <enumConstant> ]*
+}
+
+rule enumConstant {
+ <annotations>? <Identifier> <arguments>? <classBody>?
+}
+
+rule enumBodyDeclarations {
+ ';' <classBodyDeclaration>*
+}
+
+rule interfaceDeclaration {
+ | <normalInterfaceDeclaration>
+ | <annotationTypeDeclaration>
+}
+
+rule normalInterfaceDeclaration {
+ 'interface' <Identifier> <typeParameters>? ['extends' <typeList>]?
+ <interfaceBody>
+}
+
+rule typeList {
+ <type> [ ',' <type> ]*
+}
+
+rule classBody {
+ '{' <classBodyDeclaration>* '}'
+}
+
+rule interfaceBody {
+ '{' <interfaceBodyDeclaration>* '}'
+}
+
+rule classBodyDeclaration {
+ | ';'
+ | 'static'? <block>
+ | <modifiers> <memberDecl>
+}
+
+rule memberDecl {
+ | <genericMethodOrConstructorDecl>
+ | <memberDeclaration>
+ | 'void' <Identifier> <voidMethodDeclaratorRest>
+ | <Identifier> <constructorDeclaratorRest>
+ | <interfaceDeclaration>
+ | <classDeclaration>
+}
+
+rule memberDeclaration {
+ <type> [<methodDeclaration> | <fieldDeclaration>]
+}
+
+rule genericMethodOrConstructorDecl {
+ <typeParameters> <genericMethodOrConstructorRest>
+}
+
+rule genericMethodOrConstructorRest {
+ | [<type> | 'void'] <Identifier> <methodDeclaratorRest>
+ | <Identifier> <constructorDeclaratorRest>
+}
+
+rule methodDeclaration {
+ <Identifier> {*} <methodDeclaratorRest>
+}
+
+rule fieldDeclaration {
+ <variableDeclarators> ';' {*}
+}
+
+rule interfaceBodyDeclaration {
+ | <modifiers> <interfaceMemberDecl>
+ | ';'
+}
+
+rule interfaceMemberDecl {
+ | <interfaceMethodOrFieldDecl>
+ | <interfaceGenericMethodDecl>
+ | 'void' <Identifier> <voidInterfaceMethodDeclaratorRest>
+ | <interfaceDeclaration>
+ | <classDeclaration>
+}
+
+rule interfaceMethodOrFieldDecl {
+ <type> <Identifier> <interfaceMethodOrFieldRest>
+}
+
+rule interfaceMethodOrFieldRest {
+ | <constantDeclaratorsRest> ';'
+ | <interfaceMethodDeclaratorRest>
+}
+
+rule methodDeclaratorRest {
+ <formalParameters> [ '[' ']' ]*
+ ['throws' <qualifiedNameList>]?
+ [ <methodBody> | ';' ]
+}
+
+rule voidMethodDeclaratorRest {
+ <formalParameters> ['throws' <qualifiedNameList>]?
+ [ <methodBody> | ';' ]
+}
+
+rule interfaceMethodDeclaratorRest {
+ <formalParameters> [ '[' ']' ]* ['throws' <qualifiedNameList>]? ';'
+}
+
+rule interfaceGenericMethodDecl {
+ <typeParameters> [<type> | 'void'] <Identifier>
+ <interfaceMethodDeclaratorRest>
+}
+
+rule voidInterfaceMethodDeclaratorRest {
+ <formalParameters> ['throws' <qualifiedNameList>]? ';'
+}
+
+rule constructorDeclaratorRest {
+ <formalParameters> ['throws' <qualifiedNameList>]?
+ <constructorBody>
+}
+
+rule constantDeclarator {
+ <Identifier> <constantDeclaratorRest>
+}
+
+rule variableDeclarators {
+ <variableDeclarator> [ ',' <variableDeclarator> ]*
+}
+
+rule variableDeclarator {
+ <variableDeclaratorId> [ '=' <variableInitializer> ]?
+}
+
+rule constantDeclaratorsRest {
+ <constantDeclaratorRest> [ ',' <constantDeclarator> ]*
+}
+
+rule constantDeclaratorRest {
+ [ '[' ']' ]* '=' <variableInitializer>
+}
+
+rule variableDeclaratorId {
+ <Identifier> [ '[' ']' ]*
+}
+
+rule variableInitializer {
+ | <arrayInitializer>
+ | <expression>
+}
+
+rule arrayInitializer {
+ '{' [<variableInitializer> [ ',' <variableInitializer> ]* [',']? ]? '}'
+}
+
+rule modifier {
+ | <annotation>
+ | 'public'<!before \w>
+ | 'protected'<!before \w>
+ | 'private'<!before \w>
+ | 'static'<!before \w>
+ | 'abstract'<!before \w>
+ | 'final'<!before \w>
+ | 'native'<!before \w>
+ | 'synchronized'<!before \w>
+ | 'transient'<!before \w>
+ | 'volatile'<!before \w>
+ | 'strictfp'<!before \w>
+}
+
+rule packageOrTypeName {
+ <qualifiedName>
+}
+
+rule enumConstantName {
+ <Identifier>
+}
+
+rule typeName {
+ <qualifiedName>
+}
+
+rule type {
+ | <primitiveType> [ '[' ']' ]*
+ | <classOrInterfaceType> [ '[' ']' ]*
+}
+
+rule classOrInterfaceType {
+ <Identifier> <typeArguments>? [ '.' <Identifier> <typeArguments>? ]*
+}
+
+rule primitiveType {
+ | 'boolean'<!before \w>
+ | 'char'<!before \w>
+ | 'byte'<!before \w>
+ | 'short'<!before \w>
+ | 'int'<!before \w>
+ | 'long'<!before \w>
+ | 'float'<!before \w>
+ | 'double'<!before \w>
+}
+
+rule variableModifier {
+ | 'final'<!before \w>
+ | <annotation>
+}
+
+rule typeArguments {
+ '<' <typeArgument> [ ',' <typeArgument> ]* '>'
+}
+
+rule typeArgument {
+ | <type>
+ | '?' [ [ 'extends' | 'super' ] <type> ]?
+}
+
+rule qualifiedNameList {
+ <qualifiedName> [ ',' <qualifiedName> ]*
+}
+
+rule formalParameters {
+ '(' <formalParameterDecls>? ')'
+}
+
+rule formalParameterDecls {
+ <variableModifiers> <type> <formalParameterDeclsRest>
+}
+
+rule formalParameterDeclsRest {
+ | <variableDeclaratorId> [ ',' <formalParameterDecls> ]?
+ | '...' <variableDeclaratorId>
+}
+
+rule methodBody {
+ <block>
+}
+
+rule constructorBody {
+ '{' <explicitConstructorInvocation>? <blockStatement>* '}'
+}
+
+rule explicitConstructorInvocation {
+ | <nonWildcardTypeArguments>? ['this' | 'super'] <arguments> ';'
+ | <primary> '.' <nonWildcardTypeArguments>? 'super' <arguments> ';'
+}
+
+
+rule qualifiedName {
+ <Identifier> [ '.' <Identifier> ]*
+}
+
+rule literal {
+ | <HexLiteral>
+ | <OctalLiteral>
+ | <FloatingPointLiteral>
+ | <DecimalLiteral>
+ | <CharacterLiteral>
+ | <StringLiteral>
+ | <booleanLiteral>
+ | 'null'<!before \w>
+}
+
+rule booleanLiteral {
+ | 'true'<!before \w>
+ | 'false'<!before \w>
+}
+
+# // ANNOTATIONS
+
+rule annotations {
+ <annotation>+
+}
+
+rule annotation {
+ '@' <!before 'interface'\s><annotationName> {*} [ '(' [ <elementValuePairs> | <elementValue> ]? ')' ]?
+}
+
+rule annotationName {
+ <Identifier> [ '.' <Identifier> ]*
+}
+
+rule elementValuePairs {
+ <elementValuePair> [ ',' <elementValuePair> ]*
+}
+
+rule elementValuePair {
+ <Identifier> '=' <elementValue>
+}
+
+rule elementValue {
+ | <conditionalExpression>
+ | <annotation>
+ | <elementValueArrayInitializer>
+}
+
+rule elementValueArrayInitializer {
+ '{' [<elementValue> [ ',' <elementValue> ]*]? [',']? '}'
+}
+
+rule annotationTypeDeclaration {
+ '@' 'interface' <Identifier> <annotationTypeBody>
+}
+
+rule annotationTypeBody {
+ '{' [ <annotationTypeElementDeclaration> ]* '}'
+}
+
+rule annotationTypeElementDeclaration {
+ <modifiers> <annotationTypeElementRest>
+}
+
+rule annotationTypeElementRest {
+ | <type> <annotationMethodOrConstantRest> ';'
+ | <normalClassDeclaration> ';'?
+ | <normalInterfaceDeclaration> ';'?
+ | <enumDeclaration> ';'?
+ | <annotationTypeDeclaration> ';'?
+}
+
+rule annotationMethodOrConstantRest {
+ | <annotationMethodRest>
+ | <annotationConstantRest>
+}
+
+rule annotationMethodRest {
+ <Identifier> '(' ')' <defaultValue>?
+}
+
+rule annotationConstantRest {
+ <variableDeclarators>
+}
+
+rule defaultValue {
+ 'default' <elementValue>
+}
+
+# // STATEMENTS / BLOCKS
+
+rule block {
+ '{' <blockStatement>* '}' {*}
+}
+
+rule blockStatement {
+ | <localVariableDeclarationStatement>
+ | <classOrInterfaceDeclaration>
+ | <statement> {*}
+}
+
+rule localVariableDeclarationStatement {
+ <localVariableDeclaration> ';'
+}
+
+rule localVariableDeclaration {
+ <variableModifiers> <type> <variableDeclarators> {*}
+}
+
+rule variableModifiers {
+ <variableModifier>*
+}
+
+rule statement {
+ | <block>
+ | <ASSERT> <expression> [':' <expression>]? ';'
+ | 'if' <parExpression> <statement> ['else'<!before \w> <statement>]?
+ | 'for' '(' <forControl> ')' <statement>
+ | 'while' <parExpression> <statement>
+ | 'do'<!before \w> <statement> 'while' <parExpression> ';'
+ | 'try' <block>
+ [ <catches> 'finally' <block>
+ | <catches>
+ | 'finally' <block>
+ ]
+ | 'switch' <parExpression> '{' <switchBlockStatementGroups> '}'
+ | 'synchronized' <parExpression> <block>
+ | 'return'<!before \w> <expression>? ';'
+ | 'throw'<!before \w> <expression> ';'
+ | 'break'<!before \w> <Identifier>? ';'
+ | 'continue'<!before \w> <Identifier>? ';'
+ | ';'
+ | <statementExpression> ';'
+ | <!before 'case'\s><Identifier> ':' <statement>
+}
+
+rule catches {
+ [ <catchClause> ]+
+}
+
+rule catchClause {
+ 'catch' '(' <formalParameter> ')' <block>
+}
+
+rule formalParameter {
+ <variableModifiers> <type> <variableDeclaratorId>
+}
+
+rule switchBlockStatementGroups {
+ [ <switchBlockStatementGroup> ]*
+}
+
+# /* The change here (switchLabel -> switchLabel+) technically makes this grammar
+# ambiguous; but with appropriately greedy parsing it yields the most
+# appropriate AST, one in which each group, except possibly the last one, has
+# labels and statements. */
+rule switchBlockStatementGroup {
+ <switchLabel>+ <blockStatement>*
+}
+
+rule switchLabel {
+ | 'case' <constantExpression> ':' {*} #= normal
+ | 'case' <enumConstantName> ':' {*} #= enum
+ | 'default' ':' {*} #= default
+}
+
+rule forControl {
+ | <enhancedForControl>
+ | <forInit>? ';' <expression>? ';' <forUpdate>?
+}
+
+rule forInit {
+ | <localVariableDeclaration>
+ | <expressionList>
+}
+
+rule enhancedForControl {
+ <variableModifiers> <type> <Identifier> ':' <expression>
+}
+
+rule forUpdate {
+ <expressionList>
+}
+
+# // EXPRESSIONS
+
+rule parExpression {
+ '(' <expression> ')' {*}
+}
+
+rule expressionList {
+ <expression> [ ',' <expression> ]*
+}
+
+rule statementExpression {
+ <expression>
+}
+
+rule constantExpression {
+ <expression>
+}
+
+rule expression {
+ <conditionalExpression> [<assignmentOperator> <expression>]? {*}
+}
+
+rule assignmentOperator {
+ | '='
+ | '+='
+ | '-='
+ | '*='
+ | '/='
+ | '&='
+ | '|='
+ | '^='
+ | '%='
+ | '<<='
+ | '>>>='
+ | '>>='
+}
+
+rule conditionalExpression {
+ <conditionalOrExpression> [ '?' <expression> ':' <expression> ]?
+}
+
+rule conditionalOrExpression {
+ <conditionalAndExpression> [ '||' <conditionalAndExpression> ]*
+}
+
+rule conditionalAndExpression {
+ <inclusiveOrExpression> [ '&&' <inclusiveOrExpression> ]*
+}
+
+rule inclusiveOrExpression {
+ <exclusiveOrExpression> [ '|' <exclusiveOrExpression> ]*
+}
+
+rule exclusiveOrExpression {
+ <andExpression> [ '^' <andExpression> ]*
+}
+
+rule andExpression {
+ <equalityExpression> [ '&' <equalityExpression> ]*
+}
+
+rule equalityExpression {
+ <instanceOfExpression> [ ['==' | '!='] <instanceOfExpression> ]*
+}
+
+rule instanceOfExpression {
+ <relationalExpression> ['instanceof' <type>]?
+}
+
+rule relationalExpression {
+ <shiftExpression> [ <relationalOp> <shiftExpression> ]*
+}
+
+rule relationalOp {
+ | '<='
+ | '>='
+ | '<'
+ | '>'
+}
+
+rule shiftExpression {
+ <additiveExpression> [ <shiftOp> <additiveExpression> ]*
+}
+
+rule shiftOp {
+ | '<<'
+ | '>>>'
+ | '>>'
+}
+
+
+rule additiveExpression {
+ <multiplicativeExpression> [ ['+' | '-'] <multiplicativeExpression> ]*
+}
+
+rule multiplicativeExpression {
+ <unaryExpression> [ [ '*' | '/' | '%' ] <unaryExpression> ]*
+}
+
+rule unaryExpression {
+ | '+' <unaryExpression>
+ | '-' <unaryExpression>
+ | '++' <unaryExpression>
+ | '--' <unaryExpression>
+ | <unaryExpressionNotPlusMinus>
+}
+
+rule unaryExpressionNotPlusMinus {
+ | '~' <unaryExpression>
+ | '!' <unaryExpression>
+ | <castExpression>
+ | <primary> <selector>* ['++'|'--']?
+}
+
+rule castExpression {
+ | '(' <primitiveType> ')' <unaryExpression>
+ | '(' [<type> | <expression>] ')' <unaryExpressionNotPlusMinus>
+}
+
+rule primary {
+ | <parExpression>
+ | 'this'<!before \w> # added the 'before' to work around a longest-token problem
+ [ '.' <!before 'new'\s> <Identifier> ]* <IdentifierSuffix>? {*}
+ | 'super' <superSuffix>
+ | <literal>
+ | 'new' <creator>
+ | <Identifier> [ '.' <!before 'new'\s> <Identifier> ]* <IdentifierSuffix>?
+ | <primitiveType> [ '[' ']' ]* '.' 'class'
+ | 'void' '.' 'class'
+}
+
+rule IdentifierSuffix {
+ | [ '[' ']' ]+ '.' 'class'
+ | [ '[' <expression> ']' ]+ # // can also be matched by selector, but do here
+ | <arguments>
+ | '.' 'class'
+ | '.' <explicitGenericInvocation>
+ | '.' 'this'
+ | '.' 'super' <arguments>
+ | '.' 'new' <innerCreator>
+}
+
+rule creator {
+ | <nonWildcardTypeArguments> <createdName> <classCreatorRest>
+ | <createdName> [<arrayCreatorRest> | <classCreatorRest>]
+}
+
+rule createdName {
+ | <primitiveType>
+ | <classOrInterfaceType>
+}
+
+rule innerCreator {
+ <nonWildcardTypeArguments>? <Identifier> <classCreatorRest>
+}
+
+rule arrayCreatorRest {
+ '['
+ [ ']' [ '[' ']' ]* <arrayInitializer>
+ | <expression> {*} ']' [ '[' <expression> ']' ]* [ '[' ']' ]*
+ ]
+}
+
+rule classCreatorRest {
+ <arguments> <classBody>?
+}
+
+rule explicitGenericInvocation {
+ <nonWildcardTypeArguments> <Identifier> <arguments>
+}
+
+rule nonWildcardTypeArguments {
+ '<' <typeList> '>'
+}
+
+rule selector {
+ | '.' 'this'
+ | '.' 'super' <superSuffix>
+ | '.' 'new' <innerCreator>
+ | '.' <Identifier> <arguments>?
+ | '[' <expression> ']'
+}
+
+rule superSuffix {
+ <arguments>
+ | '.' <Identifier> <arguments>?
+}
+
+rule arguments {
+ '(' <expressionList>? ')'
+}
+
+# // LEXER
+
+token HexLiteral {
+ '0' ['x'|'X'] [
+ | '.' <HexDigit>+ <HexExponent>? <FloatTypeSuffix>?
+ | <HexDigit>+ [ '.' <HexDigit>* <HexExponent>? <FloatTypeSuffix>? | <IntegerTypeSuffix>? ]
+ ]
+}
+token HexDigit { \d|<[a..f]>|<[A..F]> }
+token HexExponent { ['p'|'P'] ['+'|'-']? \d+ }
+
+token OctalLiteral { '0' <[0..7]>+ <IntegerTypeSuffix>? }
+
+token DecimalLiteral { ['0'<!before \d> | <[1..9]> \d*] <IntegerTypeSuffix>? }
+token IntegerTypeSuffix { 'l'|'L' }
+
+token FloatingPointLiteral {
+ | \d+ '.' \d* <Exponent>? <FloatTypeSuffix>?
+ | '.' \d+ <Exponent>? <FloatTypeSuffix>?
+ | \d+ <Exponent> <FloatTypeSuffix>?
+ | \d+ <FloatTypeSuffix>
+}
+token Exponent { ['e'|'E'] ['+'|'-']? \d+ }
+token FloatTypeSuffix { 'f'|'F'|'d'|'D' }
+
+token CharacterLiteral { '\'' [ <EscapeSequence> | <-esc_single_quote> ] '\'' }
+token StringLiteral { '"' [ <EscapeSequence> | <-esc_double_quote> ]* '"' }
+token esc_single_quote { '\\' | '\'' }
+token esc_double_quote { '\\' | '"' }
+
+token EscapeSequence {
+ | '\\' ['b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\']
+ | <UnicodeEscape>
+ | <OctalEscape>
+}
+
+token OctalEscape {
+ '\\' [
+ | <[0..3]> <[0..7]> <[0..7]>
+ | <[0..7]> <[0..7]>
+ | <[0..7]>
+ ]
+}
+
+token UnicodeEscape { '\\u' <HexDigit>**{4} }
+
+token ENUM { 'enum'<!before \w> }
+token ASSERT { 'assert'<!before \w> }
+
+token Identifier { <!before <keyword>\W><.ident> }
+token keyword {
+ # from http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.9
+ 'abstract' | 'continue' | 'for' | 'new' | 'switch'
+ 'assert' | 'default' | 'if' | 'package' | 'synchronized'
+ 'boolean' | 'do' | 'goto' | 'private' | 'this'
+ 'break' | 'double' | 'implements' | 'protected' | 'throw'
+ 'byte' | 'else' | 'import' | 'public' | 'throws'
+ 'case' | 'enum' | 'instanceof' | 'return' | 'transient'
+ 'catch' | 'extends' | 'int' | 'short' | 'try'
+ 'char' | 'final' | 'interface' | 'static' | 'void'
+ 'class' | 'finally' | 'long' | 'strictfp' | 'volatile'
+ 'const' | 'float' | 'native' | 'super' | 'while'
+}
7 t/00-sanity.t
@@ -0,0 +1,7 @@
+# This just checks that the basic parsing and call to builtin say() works.
+say '1..4';
+say 'ok 1';
+say 'ok ', 2;
+say 'ok ', 2 + 1;
+say 'ok', ' ', 4;
+
13 t/harness
@@ -0,0 +1,13 @@
+#! perl
+
+# $Id$
+
+# pragmata
+use strict;
+use warnings;
+use 5.008;
+
+use lib qw( . lib ../lib ../../lib ../../lib );
+use Parrot::Test::Harness language => 'perk',
+ compiler => 'perk.pbc';
+

0 comments on commit 56805f4

Please sign in to comment.
Something went wrong with that request. Please try again.