Okay, this works properly and 'make test' passes, varargs functions work
fine, VISIBLE is no longer special-cased, subs aren't stuffed into
lexicals when they're defined, they're properly looked up with
find_name, a couple of fixes.

Function return values are a bit sketchy, but that's waiting on PAST
support for return statements anyway, iirc.

Functions can't return null values, as null is currently being used as
the 'end of statement' marker in expr_parse.

Optional parameters to functions aren't dealt with properly.

Auto-assignment to IT is still a bit sketchy.  I'm unsure of the proper
semantics here, but the test suite passes, so it's good enough for now.
Index: languages/lolcode/config/makefiles/root.in
===================================================================
--- languages/lolcode/config/makefiles/root.in  (revision 25607)
+++ languages/lolcode/config/makefiles/root.in  (working copy)
@@ -41,6 +41,7 @@
 
 BUILTINS_PIR = \
   src/builtins/say.pir \
+  src/builtins/expr_parse.pir \
   src/builtins/var_or_function.pir
 
 # PMCS = lolcode
Index: languages/lolcode/src/builtins/expr_parse.pir
===================================================================
--- languages/lolcode/src/builtins/expr_parse.pir       (revision 0)
+++ languages/lolcode/src/builtins/expr_parse.pir       (revision 0)
@@ -0,0 +1,146 @@
+=head1
+
+expr_parse.pir - parse an expression and dispatch function calls with their 
appropriate arguments.
+
+=cut
+
+.namespace
+
+.sub 'expr_parse'
+    .param pmc tokens :slurpy
+
+    .local pmc can_has_debug
+    can_has_debug = new 'Integer'
+
+    .local pmc t_iter
+    t_iter = new 'Iterator', tokens
+
+    .local pmc sub_stack
+    .local pmc val_stack
+    .local pmc arity_stack
+
+    sub_stack = new 'ResizablePMCArray'
+    val_stack = new 'ResizablePMCArray'
+    arity_stack = new 'ResizableIntegerArray'
+
+  it_loop:
+    unless t_iter goto it_done
+      .local pmc item
+      .local pmc sub_to_call
+      .local pmc args_array
+      item = shift t_iter
+    unless_null item, check_type
+      has_slurpy:
+      sub_to_call = pop sub_stack
+      $I0 = shift arity_stack
+      args_array = new 'ResizablePMCArray'
+      getting_varargs:
+        $P1 = pop val_stack
+        if_null $P1, call_the_sub
+        unshift args_array, $P1
+        goto getting_varargs
+      got_varargs:
+    check_type:
+      $I0 = isa item, 'Sub'
+    unless $I0 goto has_val
+      $P0 = inspect item
+      $I2 = $P0['pos_slurpy']
+      unless $I2 goto no_slurpy
+        push sub_stack, item
+        unshift arity_stack, -1
+        $P0 = null
+        push val_stack, $P0
+      goto end_fixed
+      no_slurpy:
+        $I1 = item.arity()
+        push sub_stack, item
+        unshift arity_stack, $I1
+      end_fixed:
+      goto skip_val
+    has_val:
+      push val_stack, item
+      $I0 = arity_stack[0]
+      $I0 -= 1
+      arity_stack[0] = $I0
+    skip_val:
+    call_check:
+      $I0 = arity_stack[0]
+      unless $I0 == 0 goto skip_call
+      sub_to_call = pop sub_stack
+      $I1 = sub_to_call.arity()
+      args_array = new 'ResizablePMCArray'
+    args_loop:
+      if $I1 == 0 goto args_loop_end
+      $I1 -= 1
+      $P1 = pop val_stack
+      unshift args_array, $P1
+      goto args_loop
+    args_loop_end:
+      $I2 = shift arity_stack
+      call_the_sub:
+      $P2 = sub_to_call(args_array :flat)
+      push val_stack, $P2
+      $I0 = arity_stack[0]
+      $I0 -= 1
+      arity_stack[0] = $I0
+      goto call_check
+    skip_call:
+    goto it_loop
+it_done:
+    $I0 = elements sub_stack
+    if $I0 == 0 goto no_leftover_function
+    sub_to_call = pop sub_stack
+    args_array = new 'ResizablePMCArray'
+    $P2 = new 'Iterator', val_stack
+    getting_more_varargs:
+      $I1 = elements val_stack
+      unless $I1 goto got_more_varargs
+      $P1 = pop val_stack
+      if_null $P1, got_more_varargs
+      unshift args_array, $P1
+      goto getting_more_varargs
+    got_more_varargs:
+    $P0 = sub_to_call(args_array :flat)
+    push val_stack, $P0
+    no_leftover_function:
+    .local pmc return_val 
+    return_val = pop val_stack
+    unless_null return_val, dont_return_nulls
+    return_val = new 'Integer'
+    return_val = 0
+    dont_return_nulls:
+    .return (return_val)
+.end
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:
+
Index: languages/lolcode/src/builtins/say.pir
===================================================================
--- languages/lolcode/src/builtins/say.pir      (revision 25607)
+++ languages/lolcode/src/builtins/say.pir      (working copy)
@@ -10,14 +10,20 @@
 
 .sub 'VISIBLE'
     .param pmc args            :slurpy
-    .param int no_newline      :optional :named('no_newline')
+    .local int no_newline
+    no_newline = 0
     .local pmc iter
     iter = new 'Iterator', args
   iter_loop:
     unless iter goto iter_end
-    $P0 = shift iter
-    print $P0
+    $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"
Index: languages/lolcode/src/builtins/var_or_function.pir
===================================================================
--- languages/lolcode/src/builtins/var_or_function.pir  (revision 25607)
+++ languages/lolcode/src/builtins/var_or_function.pir  (working copy)
@@ -19,7 +19,6 @@
     .return (result)
 .end
 
-
 # Local Variables:
 #   mode: pir
 #   fill-column: 100
Index: languages/lolcode/src/parser/actions.pm
===================================================================
--- languages/lolcode/src/parser/actions.pm     (revision 25607)
+++ languages/lolcode/src/parser/actions.pm     (working copy)
@@ -26,7 +26,7 @@
 
 
 method statement ($/, $key) {
-    if ($key eq 'bare_expression') {
+    if (($key eq 'expression')&&(+$<expression><tokens> == 1)) {
         my $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'), 
:viviself('Undef'));
         my $past := PAST::Op.new( :pasttype('bind'), :node( $/ ) );
         $past.push( $it );
@@ -73,28 +73,35 @@
     my $block := $( $<block> );
     $block.blocktype('declaration');
 
+    my $arglist := PAST::Stmts.new( :node($<arglist>) );
     # if there are any parameters, get the PAST for each of them and
     # adjust the scope to parameter.
-    if $<parameters> {
-        my @params := $<parameters>[0]<identifier>;
-        for @params {
-            my $param := $($_);
-            $param.scope('parameter');
-            $block.push($param);
-        }
+    $block.arity(0);
+    for $<parameters> {
+        my $param := PAST::Var.new(:name(~$_<identifier><name>), 
:scope('parameter'), :node($($_)));
+        $param.isdecl(1);
+        $arglist.push($param);
+        $block.arity($block.arity() + 1);
     }
 
+
     my $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'), 
:viviself('Undef'), :isdecl(1));
-    $block.unshift($it);
+    $block[0].unshift($it);
 
     $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'));
-    $block.push($it);
+    $block[0].push($it);
 
-    my $past := PAST::Op.new( :pasttype('bind'), :node( $/ ) );
-    $($<variable>).isdecl(1);
-    $past.push( $( $<variable> ) );
-    $past.push( $block );
-    make $past;
+    $block.unshift($arglist);
+
+    $block.name(~$<variable><identifier><name>);
+    make $block;
 }
 
 method ifthen($/) {
@@ -133,9 +140,11 @@
 
 method block($/) {
     my $past := PAST::Block.new( :blocktype('declaration'), :node( $/ ) );
+    my $stmts := PAST::Stmts.new( :node( $/ ) );
     for $<statement> {
-        $past.push( $( $_ ) );
+        $stmts.push( $( $_ ) );
     }
+    $past.push($stmts);
     make $past;
 }
 
@@ -143,14 +152,25 @@
     make $( $/{$key} );
 }
 
-method expression($/, $key) {
-    if ($key eq 'var_or_function') {
-        my $past := PAST::Op.new( :name('var_or_function'), :pasttype('call'), 
:node( $/ ) );
-        $past.push( $( $<variable> ) );
-        make $past;
-    } else {
-        make $( $/{$key} );
+method bang($/) {
+    make PAST::Val.new( :value( ~$/ ), :returns('String'), :node($/) );
+}
+
+method expression($/) {
+    my $past := PAST::Op.new( :name('expr_parse'), :pasttype('call'), :node( 
$/ ) );
+    for $<tokens> {
+        if($_<identifier>) {
+            my $inline := '%r = find_name "' ~ $_<identifier><name> ~ '"';
+            $past.push(PAST::Op.new( :inline($inline) ));
+        }
+        elsif($_ eq "MKAY"){
+            $past.push(PAST::Op.new( :inline('%r = null') ));
+        }
+        else {
+            $past.push( $( $_ ) );
+        }
     }
+    make $past;
 }
 
 method integer($/) {
Index: languages/lolcode/src/parser/grammar.pg
===================================================================
--- languages/lolcode/src/parser/grammar.pg     (revision 25607)
+++ languages/lolcode/src/parser/grammar.pg     (working copy)
@@ -19,21 +19,15 @@
 token version { \d+ [ '.' \d+ ]? }
 
 rule statement {
-    | <visible>    {*}   #= visible
     | <declare>    {*}   #= declare
     | <assign>     {*}   #= assign
     | <function>   {*}   #= function
     | <ifthen>     {*}   #= ifthen
-    | <expression> {*}   #= bare_expression
+    | <expression> {*}   #= expression
 }
 
 token statement_terminator { [ ',' | \n+ | $ ] }
 
-rule visible {
-    'VISIBLE' <expression> [ <expression> ]* [$<no_newline>='!']?
-    {*}
-}
-
 rule declare {
     'I' 'HAS' 'A' <variable> [ 'ITZ' <expression> ]?
     {*}
@@ -44,7 +38,7 @@
 }
 
 rule function {
-    'HOW' 'DUZ' 'I' <variable> <statement_terminator>
+    'HOW' 'DUZ' 'I' <variable> $<arglist>=['YR' $<parameters>=<variable>['AN' 
'YR' $<parameters>=<variable>]* ]?<statement_terminator>
     <block>
     'IF' 'U' 'SAY' 'SO'
     {*}
@@ -90,8 +84,12 @@
 }
 
 rule expression {
-    | <variable> {*}                             #= var_or_function
-    | <value> {*}                                #= value
+    [
+    | $<tokens>=<variable>
+    | $<tokens>=<value>
+    | 'AN'
+    | $<tokens>='MKAY'
+    ]+ {*}
 }
 
 rule value {
@@ -99,8 +97,13 @@
     | <integer>  {*}                             #= integer
     | <boolean>  {*}                             #= boolean
     | <quote>    {*}                             #= quote
+    | <bang>     {*}                             #= bang
 }
 
+token bang {
+'!' {*}
+}
+
 rule variable { <identifier> {*} }
 
 token identifier { <!keyword> $<name>=( <[a..zA..Z]> \w* ) {*} }
@@ -108,9 +111,9 @@
 # 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' | 'VISIBLE' | 'U' | 'SUM' | 'SO'
+    [ 'YR' | 'YA' | 'WTF?' | 'WIN' | 'WAI' | 'U' | 'SUM' | 'SO'
     | 'SMALLR' | 'SAY' | 'RLY?' | 'RLY' | 'R' | 'QUOSHUNT' | 'PRODUKT'
-    | 'OMGWTF' | 'OMG' | 'OIC' | 'O' | 'NO' | 'MOD' | 'MEBBE' | 'KTHXBYE'
+    | 'OMGWTF' | 'OMG' | 'OIC' | 'O' | 'NO' | 'MOD' | 'MKAY' | 'MEBBE' | 
'KTHXBYE'
     | 'ITZ' | 'IF' | 'I' | 'HOW' | 'HAS' | 'GTFO' | 'FOUND' | 'FAIL' | 'DIFF'
     | 'BIGGR' | 'AN' | 'A' ] >>
 }

Reply via email to