Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[lolcode] Relocating LOLCODE compiler to languages repository from

  • Loading branch information...
commit 1012194e8fa185232ab953fca329c9298415d00e 0 parents
@allisonrandal allisonrandal authored
22 Configure.pl
@@ -0,0 +1,22 @@
+# Copyright (C) 2009, Parrot Foundation.
+# $Id: Configure.pl 36945 2009-02-23 19:35:13Z fperrad $
+
+use strict;
+use warnings;
+use 5.008;
+
+my $build_dir = '../..';
+my $hll = 'lolcode';
+my $cmd = qq{$^X -Ilib tools/dev/reconfigure.pl --step=gen::languages --languages=$hll};
+
+print "Running '$cmd' in $build_dir\n";
+chdir $build_dir;
+`$cmd`
+
+# Local Variables:
+# mode: cperl
+# cperl-indent-level: 4
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:
+
8 TODO
@@ -0,0 +1,8 @@
+The following tickets were stored in parrot's RT system.
+
+They have now been marked as rejected in that system, but are listed
+here for posterity, so they can easily be migrated into lolcodes's new
+ticketing system, whatever that may be.
+
+#52178: [TODO] Improve variable declarations in LOLCODE
+ http://rt.perl.org/rt3/Ticket/Display.html?id=52178
146 config/makefiles/root.in
@@ -0,0 +1,146 @@
+# Copyright (C) 2008-2009, Parrot Foundation.
+## $Id: root.in 36930 2009-02-22 10:10:01Z barney $
+
+## arguments we want to run parrot with
+PARROT_ARGS =
+
+## configuration settings
+BUILD_DIR = @build_dir@
+LOAD_EXT = @load_ext@
+O = @o@
+EXE = @exe@
+
+## Setup some commands
+PERL = @perl@
+RM_RF = @rm_rf@
+PARROT = ../../parrot$(EXE)
+CAT = @cat@
+BUILD_DYNPMC = $(PERL) $(BUILD_DIR)/tools/build/dynpmc.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$(EXE)
+
+PMC_DIR = src/pmc
+
+all: lolcode.pbc
+
+LOLCODE_GROUP = $(PMC_DIR)/lolcode_group$(LOAD_EXT)
+
+SOURCES = lolcode.pir \
+ src/gen_grammar.pir \
+ src/gen_actions.pir \
+ src/gen_builtins.pir \
+ src/parser/yarn_literal.pir \
+# $(LOLCODE_GROUP)
+
+BUILTINS_PIR = \
+ src/builtins/say.pir \
+ src/builtins/expr_parse.pir \
+ src/builtins/math.pir \
+ src/builtins/cmp.pir
+
+# PMCS = lolcode
+# PMC_SOURCES = $(PMC_DIR)/lolcode.pmc
+
+lolcode$(EXE): lolcode.pbc
+ $(PBC_TO_EXE) lolcode.pbc
+
+installable_lolcode$(EXE): lolcode.pbc
+ $(PBC_TO_EXE) lolcode.pbc --install
+
+# the default target
+lolcode.pbc: $(PARROT) $(SOURCES)
+ $(PARROT) $(PARROT_ARGS) -o lolcode.pbc lolcode.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
+
+src/gen_builtins.pir: $(BUILTINS_PIR)
+ $(CAT) $(BUILTINS_PIR) >src/gen_builtins.pir
+
+$(LOLCODE_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
+ $(PERL) Configure.pl
+
+# 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: lolcode.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 = \
+ lolcode.pbc \
+ lolcode.c \
+ lolcode.ilk \
+ *.manifest \
+ *.pdb \
+ lolcode$(O) \
+ lolcode$(EXE) \
+ installable_lolcode$(EXE) \
+ 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:
+ $(RM_RF) $(CLEANUPS)
+
+realclean: clean
+ $(RM_RF) Makefile
+
+distclean: realclean
+
+# Local variables:
+# mode: makefile
+# End:
+# vim: ft=make:
85 lolcode.pir
@@ -0,0 +1,85 @@
+=head1 TITLE
+
+lolcode.pir - A lolcode compiler.
+
+=head2 Description
+
+This is the base file for the lolcode 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 'lolcode'.
+
+=head2 Functions
+
+=over 4
+
+=item onload()
+
+Creates the lolcode compiler using a C<PCT::HLLCompiler>
+object.
+
+=cut
+
+.HLL 'lolcode'
+
+.namespace [ 'lolcode';'Compiler' ]
+
+.loadlib 'lolcode_group'
+
+.sub '' :anon :load :init
+ load_bytecode 'PCT.pbc'
+ .local pmc parrotns, lolns, exports
+ parrotns = get_root_namespace ['parrot']
+ lolns = get_hll_namespace
+ exports = split ' ', 'PAST PCT PGE P6metaclass'
+ parrotns.'export_to'(lolns, exports)
+.end
+
+.include 'src/gen_builtins.pir'
+.include 'src/gen_grammar.pir'
+.include 'src/parser/yarn_literal.pir'
+.include 'src/gen_actions.pir'
+
+.sub 'onload' :anon :load :init
+
+ $P0 = new 'ResizablePMCArray'
+ set_hll_global ['lolcode';'Grammar';'Actions'], '@?BLOCK', $P0
+
+ $P0 = new ['PAST';'Stmts']
+ set_hll_global ['lolcode';'Grammar';'Actions'], '$?BLOCK_SIGNATURE', $P0
+
+ $P0 = get_hll_global ['PCT'], 'HLLCompiler'
+ $P1 = $P0.'new'()
+ $P1.'language'('lolcode')
+ $P0 = get_hll_namespace ['lolcode';'Grammar']
+ $P1.'parsegrammar'($P0)
+ $P0 = get_hll_namespace ['lolcode';'Grammar';'Actions']
+ $P1.'parseactions'($P0)
+.end
+
+=item main(args :slurpy) :main
+
+Start compilation by passing any command line C<args>
+to the lolcode compiler.
+
+=cut
+
+.sub 'main' :main
+ .param pmc args
+
+ $P0 = compreg 'lolcode'
+ $P1 = $P0.'command_line'(args)
+.end
+
+
+=back
+
+=cut
+
+# Local Variables:
+# mode: pir
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
+
32 src/builtins/cmp.pir
@@ -0,0 +1,32 @@
+.sub 'BOTH SAEM'
+ .param pmc x
+ .param pmc y
+ eq x, y, WIN
+ $P0 = new 'Boolean'
+ $P0 = 0
+ .return($P0)
+ WIN:
+ $P0 = new 'Boolean'
+ $P0 = 1
+ .return ($P0)
+.end
+
+.sub 'DIFFRINT'
+ .param pmc x
+ .param pmc y
+ ne x, y, WIN
+ $P0 = new 'Boolean'
+ $P0 = 0
+ .return($P0)
+ WIN:
+ $P0 = new 'Boolean'
+ $P0 = 1
+ .return ($P0)
+.end
+
+# Local Variables:
+# mode: pir
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
+
41 src/builtins/expr_parse.pir
@@ -0,0 +1,41 @@
+=head1
+
+expr_parse.pir - parse an expression and dispatch function calls with their appropriate arguments.
+
+=cut
+
+.namespace []
+
+.sub lookup
+ .param string name
+ $P0 = find_name name
+ if_null $P0, null_token
+ .return($P0)
+ null_token:
+ .return("NULL")
+.end
+
+.sub lookup_class
+ .param pmc item
+ $P0 = class item
+ $S0 = $P0
+ .return($S0)
+.end
+
+.sub defined
+ .param pmc item
+ $I0 = defined item
+ .return($I0)
+.end
+
+.sub get_inspect_info
+ .param pmc item
+ $P0 = inspect item
+ .return($P0)
+.end
+# Local Variables:
+# mode: pir
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
+
81 src/builtins/math.pir
@@ -0,0 +1,81 @@
+.sub 'SUM OF'
+ .param pmc x
+ .param pmc y
+ $P0 = add x, y
+ .return ($P0)
+.end
+
+.sub 'DIFF OF'
+ .param pmc x
+ .param pmc y
+ $P0 = sub x, y
+ .return ($P0)
+.end
+
+.sub 'PRODUKT OF'
+ .param pmc x
+ .param pmc y
+ $P0 = mul x, y
+ .return ($P0)
+.end
+
+.sub 'QUOSHUNT OF'
+ .param pmc x
+ .param pmc y
+ $P0 = div x, y
+ .return ($P0)
+.end
+
+.sub 'MOD OF'
+ .param num x
+ .param num y
+ $N0 = mod x, y
+ .return ($N0)
+.end
+
+.sub 'BIGGR OF'
+ .param pmc x
+ .param pmc y
+ $I0 = islt x, y
+ if $I0 goto y_biggr
+ .return (x)
+ y_biggr:
+ .return (y)
+.end
+
+.sub 'SMALLR OF'
+ .param pmc x
+ .param pmc y
+ $I0 = isgt x, y
+ if $I0 goto y_smallr
+ .return (x)
+ y_smallr:
+ .return (y)
+.end
+
+.sub 'FAKTORIAL OF'
+ # Get input parameter.
+ .param int n
+
+ # return (n > 1 ? n * factorial(n - 1) : 1)
+ .local int result
+
+ if n > 1 goto recurse
+ result = 1
+ goto return
+
+recurse:
+ $I0 = n - 1
+ result = 'FAKTORIAL OF'($I0)
+ result *= n
+
+return:
+ .return (result)
+.end
+
+# Local Variables:
+# mode: pir
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
+
40 src/builtins/say.pir
@@ -0,0 +1,40 @@
+# $Id: say.pir 27878 2008-05-28 14:44:03Z Whiteknight $
+
+=head1
+
+say.pir -- simple implementation of a say function
+
+=cut
+
+.namespace []
+
+.sub 'VISIBLE'
+ .param pmc args :slurpy
+ .local int no_newline
+ no_newline = 0
+ .local pmc iter
+ iter = new 'Iterator', args
+ iter_loop:
+ unless iter goto iter_end
+ $S0 = shift iter
+ $I0 = iseq $S0, '!'
+ if $I0 goto no_print
+ print $S0
+ goto iter_loop
+ no_print:
+ no_newline = 1
+ goto iter_loop
+ iter_end:
+ if no_newline goto done
+ print "\n"
+ done:
+ .return ()
+.end
+
+
+# Local Variables:
+# mode: pir
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
+
403 src/parser/actions.pm
@@ -0,0 +1,403 @@
+# Copyright (C) 2008, Parrot Foundation.
+# $Id: actions.pm 36833 2009-02-17 20:09:26Z allison $
+
+=begin comments
+
+lolcode::Grammar::Actions - ast transformations for lolcode
+
+This file contains the methods that are used by the parse grammar
+to build the PAST representation of an lolcode 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 lolcode::Grammar::Actions;
+
+method TOP($/) {
+ my $block := $( $<block> );
+ $block.symbol('IT', :scope('lexical'));
+ my $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'), :viviself('Undef'), :isdecl(1));
+ $block.unshift($it);
+ $block.hll('lolcode');
+ make $block;
+}
+
+
+method statement ($/, $key) {
+ if (($key eq 'expression')&&($<expression><tokens>[0]<identifier> ne 'VISIBLE')) {
+ my $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'), :viviself('Undef'));
+ my $past := PAST::Op.new( :pasttype('bind'), :node( $/ ) );
+ $past.push( $it );
+ $past.push( $( $<expression> ) );
+ make $past;
+ }
+ else {
+ make $( $/{$key} ); # For now
+ }
+}
+
+
+method declare($/) {
+ our $?BLOCK;
+
+ my $name := ~$<variable><identifier>;
+
+ my $var := PAST::Var.new( :name( $name ),
+ :viviself('Undef'),
+ :node( $/ )
+ );
+
+ my $scope := 'lexical';
+ if $<scope>[0] {
+ if ~$<scope>[0] eq 'FARAWAY' {
+ $scope := 'package';
+ }
+ }
+
+ $var.scope(~$scope);
+ unless $?BLOCK.symbol($name) {
+ $?BLOCK.symbol($name, :scope($scope));
+ $var.isdecl(1);
+ }
+
+ if ($<expression>) {
+ $var.isdecl(1);
+ # XXX Someone clever needs to refactor this into C<assign>
+ my $past := PAST::Op.new( :pasttype('bind'), :node( $/ ) );
+ $past.push( $var );
+ $past.push( $( $<expression>[0] ) );
+ make $past;
+ }
+ else {
+ make $var;
+ }
+}
+
+method assign($/) {
+ my $past := PAST::Op.new( :pasttype('bind'), :node( $/ ) );
+ $past.push( $( $<variable> ) );
+ $past.push( $( $<expression> ) );
+ make $past;
+}
+
+method function($/,$key) {
+ our $?BLOCK;
+ if $key eq 'params' {
+ our $?BLOCK_SIGNATURE;
+ my $arglist;
+ $arglist := PAST::Stmts.new();
+ # if there are any parameters, get the PAST for each of them and
+ # adjust the scope to parameter.
+ for $<parameters> {
+ my $param := PAST::Var.new(:name(~$_<identifier>), :scope('parameter'), :node($($_)));
+ $param.isdecl(1);
+ $arglist.push($param);
+ }
+ $?BLOCK_SIGNATURE := $arglist;
+ }
+ elsif $key eq 'block' {
+ my $block := $( $<block> );
+ $block.blocktype('declaration');
+ $?BLOCK.symbol(~$<variable><identifier>, :arity($block.arity()));
+
+ my $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'), :viviself('Undef'), :isdecl(1));
+ $block[1].unshift($it);
+
+ $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'));
+ $block[1].push($it);
+ $block.name(~$<variable><identifier>);
+ make $block;
+ #my $past := PAST::Op.new( :pasttype('bind'), :node( $/ ) );
+ #$($<variable>).isdecl(1);
+ #$past.push( $( $<variable> ) );
+ #$past.push( $block );
+ #make $past;
+ }
+
+
+
+}
+
+method ifthen($/) {
+ my $count := +$<expression> - 1;
+ my $expr := $( $<expression>[$count] );
+ my $then := $( $<block>[$count] );
+ $then.blocktype('immediate');
+ my $past := PAST::Op.new( $expr, $then,
+ :pasttype('if'),
+ :node( $/ )
+ );
+ if ( $<else> ) {
+ my $else := $( $<else>[0] );
+ $else.blocktype('immediate');
+ $past.push( $else );
+ }
+ while ($count != 0) {
+ $count := $count - 1;
+ $expr := $( $<expression>[$count] );
+ $then := $( $<block>[$count] );
+ $then.blocktype('immediate');
+ $past := PAST::Op.new( $expr, $then, $past,
+ :pasttype('if'),
+ :node( $/ )
+ );
+ }
+ $expr := $past.shift();
+ my $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'), :viviself('Undef'));
+ my $bind := PAST::Op.new( :pasttype('bind'), :node( $/ ) );
+ $bind.push( $it );
+ $bind.push( $expr );
+ $past.unshift( $it );
+ my $past := PAST::Stmts.new( $bind, $past, :node( $/ ) );
+ make $past;
+}
+
+method switch($/) {
+ my $count := +$<value> - 1;
+ my $val := $( $<value>[$count] );
+ my $then := $( $<block>[$count] );
+ my $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'), :viviself('Undef'));
+ my $expr := PAST::Op.new(:pasttype('call'), :name('BOTH SAEM'), $it, $val);
+ $then.blocktype('immediate');
+ my $past := PAST::Op.new( $expr, $then,
+ :pasttype('if'),
+ :node( $/ )
+ );
+ if ( $<else> ) {
+ my $else := $( $<else>[0] );
+ $else.blocktype('immediate');
+ $past.push( $else );
+ }
+ while ($count != 0) {
+ $count := $count - 1;
+ $val := $( $<value>[$count] );
+ $expr := PAST::Op.new(:pasttype('call'), :name('BOTH SAEM'), $it, $val);
+ $then := $( $<block>[$count] );
+ $then.blocktype('immediate');
+ $past := PAST::Op.new( $expr, $then, $past,
+ :pasttype('if'),
+ :node( $/ )
+ );
+ }
+ #$expr := $past.shift();
+ #my $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'), :viviself('Undef'));
+ #my $bind := PAST::Op.new( :pasttype('bind'), :node( $/ ) );
+ #$bind.push( $it );
+ #$bind.push( $expr );
+ #$past.unshift( $it );
+ my $past := PAST::Stmts.new( $past, :node( $/ ) );
+ make $past;
+}
+
+method block($/,$key) {
+ our $?BLOCK;
+ our @?BLOCK;
+ if $key eq 'open' {
+ our $?BLOCK_SIGNATURE;
+ $?BLOCK := PAST::Block.new( PAST::Stmts.new(), :node($/), :lexical(1) );
+ @?BLOCK.unshift($?BLOCK);
+ my $iter := $?BLOCK_SIGNATURE.iterator();
+ $?BLOCK.arity(0);
+ for $iter {
+ $?BLOCK.arity($?BLOCK.arity() + 1);
+ $?BLOCK[0].push($_);
+ $?BLOCK.symbol($_.name(), :scope('lexical'));
+ }
+ }
+ elsif $key eq 'close' {
+ #my $past := PAST::Block.new( :blocktype('declaration'), :node( $/ ) );
+ my $past := @?BLOCK.shift();
+ $?BLOCK := @?BLOCK[0];
+ my $stmts := PAST::Stmts.new( :node( $/ ) );
+ for $<statement> {
+ $stmts.push( $( $_ ) );
+ }
+ $past.push($stmts);
+ make $past;
+ }
+}
+
+method value($/, $key) {
+ make $( $/{$key} );
+}
+
+method bang($/) {
+ make PAST::Val.new( :value( ~$/ ), :returns('String'), :node($/) );
+}
+
+sub find_in_blocks($name) {
+ our $?BLOCK;
+ our @?BLOCK;
+ if $?BLOCK.symbol(~$name) {
+ return $?BLOCK.symbol($name);
+ }
+ for @?BLOCK {
+ if $_.symbol(~$name) { return $_.symbol($name); }
+ }
+ return 0;
+}
+
+sub is_sub($name) {
+ my $sym := find_in_blocks($name);
+ if $sym && defined($sym<arity>) { return 1; }
+ my $lex := lookup($name);
+ if lookup_class($lex) eq 'Sub' { return 1; }
+ return 0;
+}
+
+sub get_item($name) {
+ if is_sub($name) {
+ return PAST::Op.new( :name($name), :pasttype('call') );
+ }
+ else {
+ my $var := PAST::Var.new(:name($name));
+ my $sym := find_in_blocks($name);
+ if $sym && defined($sym<scope>) { $var<scope> := $sym<scope> }
+ return $var;
+ }
+}
+
+sub get_arity($name) {
+ my $sym := find_in_blocks($name);
+ if $sym {
+ return $sym<arity>;
+ }
+ else {
+ my $lex := lookup($name);
+ my $ii := get_inspect_info($lex);
+ if $ii<pos_slurpy> {
+ return -1;
+ }
+ else {
+ return $lex.arity();
+ }
+ }
+}
+
+method expression($/) {
+ my @subs;
+ my @vals;
+ my @arity;
+ my $mkay := 'mkay';
+
+ for $<tokens> {
+ if($_<identifier>) {
+ my $name := ~$_<identifier>;
+ my $item := get_item($name);
+ if is_sub($name) {
+ my $arity := get_arity($name);
+ $item<arity> := $arity;
+ @subs.push($item);
+ @arity.unshift($arity + 0);
+ if @arity[0] == -1 { @vals.push($mkay) }
+ }
+ else {
+ @vals.push($item);
+ if defined(@arity[0]) {@arity[0]--};
+ }
+ }
+ else {
+ my $item := $( $_ );
+ @vals.push($item);
+ if defined(@arity[0]) {@arity[0]--};
+ }
+
+ while defined(@arity[0]) && @arity[0] == 0 {
+ my $sub := @subs.pop();
+ @arity.shift();
+ my $arity := $sub<arity> + 0;
+ while $arity > 0 {
+ $sub.unshift(@vals.pop());
+ $arity--;
+ }
+ @vals.push($sub);
+ if defined(@arity[0]) {@arity[0]--};
+ }
+ }
+
+ if @vals[0] eq $mkay {
+ @vals.shift();
+ my $sub := @subs.pop();
+ while +@vals {
+ $sub.unshift(@vals.pop());
+ }
+ @vals.push($sub);
+ }
+ make @vals[0];
+}
+
+method integer($/) {
+ make PAST::Val.new( :value( ~$/ ), :returns('Integer'), :node($/) );
+}
+
+method float($/) {
+ make PAST::Val.new( :value( ~$/ ), :returns('Float'), :node($/) );
+}
+
+method boolean($/) {
+ if (~$/ eq 'FAIL' ) {
+ make PAST::Val.new( :value( 0 ), :returns('Boolean'), :node($/) );
+ }
+ else {
+ make PAST::Val.new( :value( 1 ), :returns('Boolean'), :node($/) );
+ }
+}
+
+method quote($/) {
+ make PAST::Val.new( :value( $($<yarn_literal>) ), :node($/) );
+}
+
+
+method variable ($/) {
+ if ($<identifier> eq 'IT') {
+ make PAST::Var.new( :name( 'IT' ), :scope('lexical'), :viviself('Undef'));
+ }
+ else {
+ our $?BLOCK;
+
+ my $var := PAST::Var.new( :name( $<identifier> ),
+ :scope('lexical'),
+ :viviself('Undef'),
+ :node( $/ )
+ );
+ if $?BLOCK.symbol($<identifier>) {
+ my $scope := '' ~ $?BLOCK.symbol($<identifier>)<scope>;
+ $var.scope(~$scope);
+ }
+ else {
+ our @?BLOCK;
+ my $exists := 0;
+ my $scope;
+ for @?BLOCK {
+ if $_ {
+ my $sym_table := $_.symbol(~$<identifier>);
+ if $sym_table {
+ $exists := 1;
+ $scope := '' ~ $sym_table<scope>;
+ }
+ }
+ }
+ if $exists == 0 {
+ $var.scope('package');
+ }
+ else {
+ $var.scope($scope);
+ }
+ }
+
+ make $var;
+ }
+}
+
+
+# Local Variables:
+# mode: cperl
+# cperl-indent-level: 4
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:
+
149 src/parser/grammar.pg
@@ -0,0 +1,149 @@
+# $Id: grammar.pg 29257 2008-07-10 20:41:17Z tene $
+
+=begin overview
+
+This is the grammar for lolcode written as a sequence of Perl 6 rules.
+
+=end overview
+
+grammar lolcode::Grammar is PCT::Grammar;
+
+rule TOP {
+ ['HAI' <version> <.statement_terminator>]?
+ <block>
+ ['KTHXBYE' <.statement_terminator>]?
+ [ $ || <panic: 'Syntax error'> ]
+ {*}
+}
+
+token version { \d+ [ '.' \d+ ]? }
+
+rule statement {
+ | <declare> {*} #= declare
+ | <assign> {*} #= assign
+ | <function> {*} #= function
+ | <ifthen> {*} #= ifthen
+ | <switch> {*} #= switch
+ | <expression> {*} #= expression
+}
+
+token statement_terminator { [ ',' | \n+ | $ ] }
+
+rule declare {
+ 'I' 'HAS' 'A' <scope>? <variable> [ 'ITZ' <expression> ]?
+ {*}
+}
+
+token scope {
+ | 'FARAWAY'
+ | 'NEARBY'
+}
+
+rule assign {
+ <variable> 'R' <expression> {*}
+}
+
+rule function {
+ # $<parameters> is only getting the first parameter, not all of them
+ # like I'd expect...
+ 'HOW' 'DUZ' 'I' <variable> ['YR' $<parameters>=<variable> [ 'AN' 'YR' $<parameters>=<variable>]* ]?<.statement_terminator>
+ {*} #= params
+ <block>
+ 'IF' 'U' 'SAY' 'SO'
+ {*} #= block
+}
+
+rule ifthen {
+ <expression> <.statement_terminator>
+ 'O' 'RLY?' <.statement_terminator>
+ 'YA' 'RLY' <.statement_terminator>
+ <block>
+ [
+ 'MEBBE' <expression> <.statement_terminator>
+ <block>
+ ]*
+ [
+ 'NO' 'WAI' <.statement_terminator>
+ $<else>=<block>
+ ]?
+ 'OIC'
+ {*}
+}
+
+rule switch {
+ 'WTF?' <.statement_terminator>
+ [
+ 'OMG' <value> <.statement_terminator>
+ <block>
+ ]+
+ [
+ 'OMGWTF' <.statement_terminator>
+ <else=block>
+ ]?
+ 'OIC' {*}
+}
+
+rule block {
+ {*} #= open
+ [<statement> <.statement_terminator>]*
+ {*} #= close
+}
+
+rule parameters {
+ 'YR' <identifier> [ 'AN' 'YR' <identifier> ]*
+}
+
+rule expression {
+ [
+ | $<tokens>=<operator>
+ | $<tokens>=<variable>
+ | $<tokens>=<value>
+ | 'AN'
+ | $<tokens>='MKAY'
+ ]+ {*}
+}
+
+token value {
+ | <float> {*} #= float
+ | <integer> {*} #= integer
+ | <boolean> {*} #= boolean
+ | <quote> {*} #= quote
+ | <bang> {*} #= bang
+}
+
+token bang {
+ '!' {*}
+}
+
+token operator { $<identifier>=(<.identifier> <.ws> 'OF'|'BOTH SAEM') {*} }
+token variable { <identifier> {*} }
+
+token identifier { <!keyword> <[a..zA..Z]> \w* }
+
+# RT #46213 : Because PGE doesn't yet know how to do longest token matching,
+# order all tokens in reverse alpha order to avoid a parsing bug.
+token keyword {
+ [ 'YR' | 'YA' | 'WTF?' | 'WIN' | 'WAI' | 'U' | 'SO'
+ | 'SAY' | 'RLY?' | 'RLY' | 'R'
+ | 'OMGWTF' | 'OMG' | 'OIC' | 'OF' | 'O' | 'NO' | 'MKAY' | 'MEBBE' | 'KTHXBYE'
+ | 'ITZ' | 'IF' | 'I' | 'HOW' | 'HAS' | 'GTFO' | 'FOUND' | 'FARAWAY' | 'FAIL'
+ | 'AN' | 'A' ] >>
+}
+
+token integer { '-'? \d+ {*} }
+
+token float { '-'? \d+ '.' \d+ {*} }
+
+rule boolean { [ 'WIN' | 'FAIL' ] {*} }
+
+rule quote {
+ [ <.before '"'> <yarn_literal> ]
+ {*}
+}
+
+token ws { <!ww> [
+ | ^^ \h* BTW \h \N* \n+
+ | ^^ \h* OBTW .*? ^^ \h* TLDR \n+
+ | \h+
+ ]*
+}
97 src/parser/yarn_literal.pir
@@ -0,0 +1,97 @@
+# $Id: yarn_literal.pir 31862 2008-10-10 18:23:45Z tene $
+
+.namespace ['lolcode';'Grammar']
+
+.sub 'yarn_literal' :method
+ .param pmc adverbs :slurpy :named
+
+ .local string delim
+ delim = '"'
+
+ ## create a new match object, get the new match position
+ .local pmc mob
+ .local int pos, lastpos, delimlen
+ .local string target
+ (mob, pos, target) = self.'new'(self)
+ lastpos = length target
+
+ ## leave space for close delimiter
+ delimlen = length delim
+ lastpos -= delimlen
+
+ ## now initialize and loop through target
+ literal_init:
+ .local string literal, litchar, escaped
+ literal = ''
+ litchar = substr target, pos, 1
+ inc pos
+ if litchar == delim goto literal_loop
+ self.'panic'('Missing open delimiter for YARN literal.')
+
+ literal_loop:
+ ## if we're beyond the last possible position, fail
+ if pos > lastpos goto fail
+
+ ## get next character in literal
+ litchar = substr target, pos, 1
+ inc pos
+ if litchar == delim goto literal_end
+
+ ## add non-escape characters to literal
+ if litchar != ':' goto add_litchar
+
+ ## interpolate escaped
+ escaped = substr target, pos, 1
+ $I0 = index ':)>o"(', escaped
+ if $I0 < 0 goto add_litchar
+ inc pos
+ if $I0 == 5 goto scan_hexchar
+
+ litchar = substr ":\n\t\a\"", $I0, 1
+ goto add_litchar
+
+ scan_hexchar:
+ .local int decnum
+ decnum = 0
+
+ scan_hexchar_loop:
+ if pos > lastpos goto fail
+ $S0 = substr target, pos, 1
+ inc pos
+ if $S0 == ')' goto add_hexchar
+ $I0 = index '0123456789abcdefABCDEF', $S0
+ if $I0 < 0 goto fail_hexchar
+ if $I0 < 16 goto shift_hexchar
+ $I0 -= 6
+ shift_hexchar:
+ decnum *= 16
+ decnum += $I0
+ goto scan_hexchar_loop
+
+ fail_hexchar:
+ self.'panic'('Invalid character in hex escape.')
+
+ add_hexchar:
+ litchar = chr decnum
+ goto add_litchar
+
+ add_litchar:
+ literal .= litchar
+ goto literal_loop
+
+ literal_end:
+ mob.'to'(pos)
+ mob.'result_object'(literal)
+ .return (mob)
+
+ fail:
+ mob.'to'(-1)
+ .return (mob)
+.end
+
+
+# Local Variables:
+# mode: pir
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
25 t/00-sanity.t
@@ -0,0 +1,25 @@
+HAI 1.2
+ VISIBLE "1..5"
+ BTW THIS IS COMMENT OK?
+
+ VISIBLE "ok 1"
+
+ BTW VISIBLE IS SLURPY
+ VISIBLE "ok " 2
+
+ OBTW this is a multi-line comment.
+ more.
+ VISIBLE "nok 3"
+ TLDR
+ VISIBLE "ok 3"
+
+ BTW VISIBLE WITHOUT CARRIAGE RETURN
+ VISIBLE "o" !
+ VISIBLE "k 4"
+
+ BTW SLURPY VISIBLE WITHOUT CARRIAGE RETURN
+ VISIBLE "o" "k" " " 5 !
+ VISIBLE ""
+
+ BTW vim: set filetype=lolcode :
+KTHXBYE
35 t/01-vars.t
@@ -0,0 +1,35 @@
+HAI 1.2
+ VISIBLE "1..6"
+
+ BTW THIS IS COMMENT OK?
+ I HAS A CHEEZBURGER ITZ "ok "
+ VISIBLE CHEEZBURGER !
+ CHEEZBURGER R 1
+ VISIBLE CHEEZBURGER
+
+ BTW ONE LETTER VARS OK.
+ I HAS A Q ITZ "ok "
+ VISIBLE Q !
+ Q R 2
+ VISIBLE Q
+
+ BTW BARE EXPRESSIONS SET "IT"
+ "ok 3"
+ VISIBLE IT
+
+ BTW VARS THAT START WITH KEYWORDS OK.
+ I HAS A ANY ITZ "ok 4"
+ VISIBLE ANY
+
+ BTW EMPTY DECLARATIONS SHOULDN'T CLOBBER
+ I HAS A RESULT ITZ "ok 5"
+ I HAS A RESULT
+ VISIBLE RESULT
+
+ BTW MULTIPLE DECLARATIONS WITH ASSIGNMENTS SHOULD CLOBBER
+ I HAS A ANOTHER ITZ "not ok 6"
+ I HAS A ANOTHER ITZ "ok 6"
+ VISIBLE ANOTHER
+
+ BTW vim: set filetype=lolcode :
+KTHXBYE
55 t/02-functions.t
@@ -0,0 +1,55 @@
+HAI 1.2
+ VISIBLE "1..9"
+
+ OBTW
+ Function names in this file conform to RFC 3092.
+ http://www.faqs.org/rfcs/rfc3092.html
+ TLDR
+
+ BTW SANITY CHECK
+ HOW DUZ I foo
+ VISIBLE "ok 1"
+ IF U SAY SO
+
+ foo
+
+ BTW FUNCTIONS SHOULD RETURN IT
+ HOW DUZ I bar
+ "ok 3"
+ VISIBLE "ok 2"
+ IF U SAY SO
+
+ VISIBLE bar
+
+ BTW FUNCTIONS SHOULD ONLY BE EVALUATED ONCE
+ HOW DUZ I baz
+ "ok 5"
+ VISIBLE "ok 4"
+ IF U SAY SO
+
+ I HAS A RESULT ITZ baz
+
+ VISIBLE RESULT
+
+ BTW VARIABLES SHOULD BE LOCAL TO A FUNCTION
+ HOW DUZ I qux
+ I HAS A VAR ITZ "nok 7"
+ VISIBLE "ok 6"
+ IF U SAY SO
+
+ I HAS A VAR ITZ "ok 7"
+ qux
+ VISIBLE VAR
+
+ BTW IT SHOULD ALSO BE LOCAL TO A FUNCTION
+ HOW DUZ I quux
+ "nok 9"
+ VISIBLE "ok 8"
+ IF U SAY SO
+
+ "ok 9"
+ VAR R quux
+ VISIBLE IT
+
+ BTW vim: set filetype=lolcode :
+KTHXBYE
169 t/03-if.t
@@ -0,0 +1,169 @@
+HAI 1.2
+ VISIBLE "1..16"
+
+ BTW SANITY CHECK
+ WIN
+ O RLY?
+ YA RLY
+ VISIBLE "ok 1"
+ NO WAI
+ VISIBLE "nok 1"
+ OIC
+
+ BTW ANOTHER SANITY CHECK
+ FAIL
+ O RLY?
+ YA RLY
+ VISIBLE "nok 2"
+ NO WAI
+ VISIBLE "ok 2"
+ OIC
+
+ BTW DON'T BLINDLY EVALUATE THE SECOND BLOCK AFTER FAIL
+ FAIL
+ O RLY?
+ YA RLY
+ VISIBLE "nok 3"
+ MEBBE FAIL
+ VISIBLE "nok 3"
+ MEBBE WIN
+ VISIBLE "ok 3"
+ NO WAI
+ VISIBLE "nok 3"
+ OIC
+
+ BTW BARE EXPRESSION SHOULD SET IT EVEN IF PART OF O RLY?
+ 4
+ O RLY?
+ YA RLY
+ VISIBLE "ok " IT
+ NO WAI
+ VISIBLE "nok 4"
+ OIC
+
+ BTW ZERO IS FAIL
+ 0
+ O RLY?
+ YA RLY
+ VISIBLE "nok 5"
+ NO WAI
+ VISIBLE "ok 5"
+ OIC
+
+ BTW NON-EMPTY YARN IS WIN
+ "ok 6"
+ O RLY?
+ YA RLY
+ VISIBLE IT
+ NO WAI
+ VISIBLE "nok 6"
+ OIC
+
+ BTW EMPTY YARN IS FAIL
+ ""
+ O RLY?
+ YA RLY
+ VISIBLE "nok 7"
+ NO WAI
+ VISIBLE "ok " IT "7"
+ OIC
+
+ BTW IGNORE MEBBE AFTER WIN
+ "ok 8"
+ O RLY?
+ YA RLY
+ VISIBLE IT
+ MEBBE "nok 8"
+ VISIBLE "nok 8"
+ NO WAI
+ VISIBLE "nok 8"
+ OIC
+
+ BTW VARIABLES CAN BE USED WITH O RLY?
+ I HAS A CHEEZBURGER ITZ FAIL
+ CHEEZBURGER
+ O RLY?
+ YA RLY
+ VISIBLE "nok 9"
+ NO WAI
+ VISIBLE "ok 9"
+ OIC
+
+ BTW MORE FUN WITH VARIABLEs
+ CHEEZBURGER R "ok 10"
+ CHEEZBURGER
+ O RLY?
+ YA RLY
+ VISIBLE IT
+ NO WAI
+ VISIBLE "nok 10"
+ OIC
+
+ BTW BARE EXPRESSIONS IN o RLY? CHANGE VALUE OF IT
+ WIN
+ O RLY?
+ YA RLY
+ "ok 11"
+ VISIBLE IT
+ NO WAI
+ "nok 11"
+ VISIBLE IT
+ OIC
+
+ BTW CHECK PROPER HANDLING OF IT
+ "ok 12"
+ IT
+ O RLY?
+ YA RLY
+ VISIBLE IT
+ "ok 13"
+ NO WAI
+ VISIBLE "nok 12"
+ "nok 12"
+ OIC
+ BTW KEEP THESE TESTS TOGETHER
+ IT
+ O RLY?
+ YA RLY
+ VISIBLE IT
+ NO WAI
+ VISIBLE "nok 13"
+ OIC
+
+ BTW NESTED O RLY?
+ FAIL
+ O RLY?
+ YA RLY
+ VISIBLE "nok 14"
+ NO WAI
+ "ok 14"
+ O RLY?
+ YA RLY
+ IT
+ O RLY?
+ YA RLY
+ VISIBLE IT
+ NO WAI
+ VISIBLE "nok 14"
+ OIC
+ NO WAI
+ VISIBLE "nok 14"
+ OIC
+ OIC
+
+ BTW O RLY? SHOULD ONLY CALL A FUNCTION ONCE WHEN SETTING IT
+ HOW DUZ I ReturnWin
+ VISIBLE "ok 15"
+ "ok 16"
+ IF U SAY SO
+
+ ReturnWin
+ O RLY?
+ YA RLY
+ VISIBLE IT
+ NO WAI
+ VISIBLE "nok 16"
+ OIC
+
+ BTW vim: set filetype=lolcode :
+KTHXBYE
15 t/04-strings.t
@@ -0,0 +1,15 @@
+HAI 1.2
+ VISIBLE "1..4"
+
+ BTW SIMPLE ESCAPE
+ VISIBLE "ok 1 :)" !
+
+ BTW SIMPLE ESCAPE WITH MULTIPLE ARGS
+ VISIBLE "ok 2" ":)" "ok 3"
+
+ BTW HEX ESCAPE "ok 4"
+ VISIBLE ":(6f):(6B):(20):(34)" !
+ VISIBLE " # I :(2665) Unicode"
+
+ BTW vim: set filetype=lolcode :
+KTHXBYE
38 t/05-math.t
@@ -0,0 +1,38 @@
+HAI 1.2
+ VISIBLE "1..11"
+
+ BTW 1
+ VISIBLE "ok " SUM OF -2 AN 3
+
+ BTW 2
+ VISIBLE "ok " DIFF OF -1 AN -3
+
+ BTW 3
+ VISIBLE "ok " SUM OF 1 AN SUM OF 1 AN 1
+
+ BTW 4
+ VISIBLE "ok " PRODUKT OF 2 AN 2
+
+ BTW 5
+ VISIBLE "ok " QUOSHUNT OF 10 AN 2
+
+ BTW 6
+ VISIBLE "ok " MOD OF 27 AN 7
+
+ BTW 7
+ VISIBLE "ok " BIGGR OF 6 AN 7
+
+ BTW 8
+ VISIBLE "ok " SMALLR OF 8 AN 9
+
+ BTW 9
+ VISIBLE "ok " PRODUKT OF 4.5 AN 2
+
+ BTW 10
+ I HAS A CHEEZBURGER ITZ PRODUKT OF 5 AN 2
+ VISIBLE "ok " CHEEZBURGER
+
+ BTW 11
+ CHEEZBURGER R SUM OF CHEEZBURGER AN 1
+ VISIBLE "ok " CHEEZBURGER
+KTHXBYE
22 t/06-functionparams.t
@@ -0,0 +1,22 @@
+HAI 1.2
+ VISIBLE "1..3"
+
+ BTW MAEK AN OKAY FUNCTION
+ HOW DUZ I OKAY YR NUM
+ VISIBLE "ok " NUM
+ IF U SAY SO
+
+ I HAS A TESTNUM ITZ 1
+ OKAY TESTNUM
+
+ HOW DUZ I PASSTWOTESTS YR first AN YR second
+ OKAY first
+ OKAY second
+ IF U SAY SO
+
+ TESTNUM R 2
+
+ PASSTWOTESTS TESTNUM SUM OF TESTNUM AN 1
+
+ BTW vim: set filetype=lolcode :
+KTHXBYE
24 t/07-globals.t
@@ -0,0 +1,24 @@
+HAI 1.2
+
+ HOW DUZ I setup
+ VISIBLE "1..2"
+ I HAS A FARAWAY testcount ITZ 1
+ IF U SAY SO
+
+ HOW DUZ I increment
+ I HAS A FARAWAY testcount
+ testcount R SUM OF testcount AN 1
+ IF U SAY SO
+
+ HOW DUZ I report
+ I HAS A FARAWAY testcount
+ VISIBLE "ok " AN testcount
+ IF U SAY SO
+
+ setup
+ report
+ increment
+ report
+
+ BTW vim: set filetype=lolcode :
+KTHXBYE
68 t/08-switch.t
@@ -0,0 +1,68 @@
+HAI 1.2
+ VISIBLE "1..6"
+
+ BTW SANITY CHECK
+ WIN
+ WTF?
+ OMG WIN
+ VISIBLE "ok 1"
+ OMGWTF
+ VISIBLE "not ok 1"
+ OIC
+
+ BTW ANOTHER SANITY CHECK
+ FAIL
+ WTF?
+ OMG WIN
+ VISIBLE "not ok 2"
+ OMGWTF
+ VISIBLE "ok 2"
+ OIC
+
+ BTW LITERAL
+ "CHEEZBURGER"
+ WTF?
+ OMG "CHEEZBURGER"
+ VISIBLE "ok 3"
+ OMGWTF
+ VISIBLE "not ok 3"
+ OIC
+
+ BTW VARIABLE MATCHES FIRST CASE
+ I HAS A CHEEZBURGER ITZ 1
+ CHEEZBURGER
+ WTF?
+ OMG 1
+ VISIBLE "ok 4"
+ OMG 2
+ VISIBLE "ok 4"
+ OMGWTF
+ VISIBLE "not ok 4"
+ OIC
+
+ BTW VARIABLE MATCHES SECOND CASE
+ CHEEZBURGER R 2
+ CHEEZBURGER
+ WTF?
+ OMG 1
+ VISIBLE "not ok 5"
+ OMG 2
+ VISIBLE "ok 5"
+ OMGWTF
+ VISIBLE "not ok 5"
+ OIC
+
+ BTW VARIABLE DOESN'T MATCH
+ CHEEZBURGER R 3
+ CHEEZBURGER
+ WTF?
+ OMG 1
+ VISIBLE "not ok 6"
+ OMG 2
+ VISIBLE "not ok 6"
+ OMGWTF
+ VISIBLE "ok 6"
+ OIC
+
+ BTW vim: set filetype=lolcode :
+KTHXBYE
49 t/99-four-fours.t
@@ -0,0 +1,49 @@
+HAI 1.2
+ VISIBLE "1..20"
+
+ BTW 1
+ VISIBLE "ok " SUM OF QUOSHUNT OF 4 AN 4 AN DIFF OF 4 AN 4
+
+ BTW 2
+ VISIBLE "ok " SUM OF QUOSHUNT OF 4 AN 4 AN QUOSHUNT OF 4 AN 4
+
+ BTW 3
+ VISIBLE "ok " QUOSHUNT OF SUM OF SUM OF 4 AN 4 AN 4 AN 4
+
+ BTW 4
+ VISIBLE "ok " SUM OF PRODUKT OF DIFF OF 4 AN 4 AN 4 AN 4
+
+ BTW 5
+ VISIBLE "ok " QUOSHUNT OF SUM OF PRODUKT OF 4 AN 4 AN 4 AN 4
+
+ BTW 6
+ VISIBLE "ok " SUM OF QUOSHUNT OF SUM OF 4 AN 4 AN 4 AN 4
+ BTW 7
+ VISIBLE "ok " DIFF OF SUM OF 4 AN 4 AN QUOSHUNT OF 4 AN 4
+ BTW 8
+ VISIBLE "ok " DIFF OF SUM OF 4 AN 4.4 AN 0.4
+ BTW 9
+ VISIBLE "ok " SUM OF SUM OF 4 AN 4 AN QUOSHUNT OF 4 AN 4
+ BTW 10
+ VISIBLE "ok " QUOSHUNT OF DIFF OF 44 AN 4 AN 4
+ BTW 11
+ VISIBLE "ok " SUM OF QUOSHUNT OF 4 AN 0.4 AN QUOSHUNT OF 4 AN 4
+ BTW 12
+ VISIBLE "ok " QUOSHUNT OF SUM OF 44 AN 4 AN 4
+ BTW 13
+ VISIBLE "ok " DIFF OF FAKTORIAL OF 4 AN QUOSHUNT OF 44 AN 4
+ BTW 14
+ VISIBLE "ok " DIFF OF PRODUKT OF 4 AN DIFF OF 4 AN 0.4 AN 0.4
+ BTW 15
+ VISIBLE "ok " DIFF OF PRODUKT OF 4 AN 4 AN QUOSHUNT OF 4 AN 4
+ BTW 16
+ VISIBLE "ok " QUOSHUNT OF PRODUKT OF PRODUKT OF 4 AN 4 AN 4 AN 4
+ BTW 17
+ VISIBLE "ok " SUM OF PRODUKT OF 4 AN 4 AN QUOSHUNT OF 4 AN 4
+ BTW 18
+ VISIBLE "ok " SUM OF PRODUKT OF 44 AN 0.4 AN 0.4
+ BTW 19
+ VISIBLE "ok " DIFF OF DIFF OF FAKTORIAL OF 4 AN 4 AN QUOSHUNT OF 4 AN 4
+ BTW 20
+ VISIBLE "ok " PRODUKT OF 4 AN SUM OF QUOSHUNT OF 4 AN 4 AN 4
+KTHXBYE
8 t/harness
@@ -0,0 +1,8 @@
+#! perl
+
+# $Id: harness 24466 2008-01-03 04:43:35Z coke $
+
+use FindBin;
+use lib qw( . lib ../lib ../../lib );
+use Parrot::Test::Harness language => 'lolcode', compiler => 'lolcode.pbc';
+

0 comments on commit 1012194

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