Author: coke
Date: Tue Aug  9 07:16:31 2005
New Revision: 8886

Modified:
   trunk/languages/tcl/lib/commands/proc.pir
   trunk/languages/tcl/t/cmd_proc.t
Log:
tcl: add support for [proc {a b args} {}], as well as tests.



Modified: trunk/languages/tcl/lib/commands/proc.pir
==============================================================================
--- trunk/languages/tcl/lib/commands/proc.pir   (original)
+++ trunk/languages/tcl/lib/commands/proc.pir   Tue Aug  9 07:16:31 2005
@@ -65,36 +65,94 @@ got_args:
   .local string proc_body
   proc_body  = ".namespace [\"Tcl\"]\n.sub \"&"
   proc_body .= name
-  proc_body .= "\"\n.param pmc args\nargs = foldup\nnew_pad 1\n"
-  proc_body .= ".local pmc call_level\ncall_level = find_global \"_Tcl\", 
\"call_level\"\ninc call_level\n"
+  proc_body .= "\"\n  .local pmc args\n  args = foldup\n  new_pad 1\n  "
+  proc_body .= ".local pmc call_level\n  call_level = find_global \"_Tcl\", 
\"call_level\"\n  inc call_level\n  "
   .local int arg_count 
   arg_count = args_p
-  .local int ii
+  .local int ii,is_slurpy
+  is_slurpy = 0 
   ii = 0
+  if arg_count == 0 goto arg_loop_done
+  $I0 = arg_count - 1
+  $S0 = args_p[$I0]
+
+  .local int last_arg
+  last_arg = arg_count
+
+  if $S0 != "args" goto check_args
+  is_slurpy = 1
+  dec last_arg
+
+check_args:
+  proc_body .= ".local int argc\n  argc=args\n  "
+
+  if is_slurpy goto slurpy_arg_count
+  proc_body .= "if argc != "
+  $S0 = arg_count
+  proc_body .=  $S0
+  proc_body .= " goto BAD_ARGS\n\n"
+  goto arg_loop
+  
+
+slurpy_arg_count:
+  proc_body .= "if argc < "
+  $I0 = arg_count - 1
+  $S0 = $I0
+  proc_body .=  $S0
+  proc_body .= " goto BAD_ARGS\n  "
+
 arg_loop:
-  if ii == arg_count goto arg_loop_done
+  if ii == last_arg goto arg_loop_done
   $S1 = ii
   proc_body .= "$P1 = args["
   proc_body .= $S1
-  proc_body .= "]\nstore_lex -1,\"$"
+  proc_body .= "]\n  "
+  proc_body .= "store_lex -1,\"$"
   # XXX This should be Escape'd
   $S1 = args_p[ii]
   proc_body .= $S1
-  proc_body .= "\", $P1\n"
+  proc_body .= "\", $P1\n  "
   ii = ii + 1
   goto arg_loop
+
 arg_loop_done:
+  unless is_slurpy goto body
+
+  # Convert the remaining elements returned by foldup into a TclList
+  # XXX This code lifted from Tcl::&list - eventually factor this out.
+  proc_body .= ".local int cnt,jj\n  cnt = "
+  $I0 = ii
+  $S0 = $I0
+  proc_body .= $S0
+  proc_body .= "\n  jj = 0\n  "
+  #proc_body .= "$I0 = argc - 1\n  "
+  proc_body .= "if cnt == argc goto NO_SLURPY_ARGS\n  "
+  
+  proc_body .= ".local pmc arg_list\n  arg_list = new .TclList\n  "
+  proc_body .= "\n\nSLURPY_LOOP:\n  "
+  proc_body .= "if cnt >= argc goto DONE\n  "
+  proc_body .= "$P0 = args[cnt]\n  "
+  proc_body .= "arg_list[jj] = $P0\n  "
+  proc_body .= "inc cnt\n  "
+  proc_body .= "inc jj\n  "
+  proc_body .= "goto SLURPY_LOOP\n\n"
+  proc_body .= "NO_SLURPY_ARGS:\n  arg_list= new .TclString\n  
arg_list=\"\"\n\n"
+  proc_body .= "DONE:\n  "
+  proc_body .= "store_lex -1, \"$args\", arg_list\n  "
+  
 
-  proc_body .= ".local pmc interpret\ninterpret = find_global \"_Tcl\", 
\"__interpret\"\n.local pmc proc_body\n$P0 = find_global \"_Tcl\", 
\"proc_parsed\"\nproc_body=$P0[\""
+body:
+  proc_body .= ".local pmc interpret\n  interpret = find_global \"_Tcl\", 
\"__interpret\"\n  .local pmc proc_body\n  $P0 = find_global \"_Tcl\", 
\"proc_parsed\"\n  proc_body=$P0[\""
   proc_body .= esc_name
-  proc_body .= "\"]\nif I3 == "
-  $S1 = arg_count
-  proc_body .= $S1
-  proc_body .= " goto args_ok\nbad_args:\n.return(1,\"wrong # args: should be 
\\\""
+  proc_body .= "\"]\n  "
+
+done_args:
+  proc_body .= "  goto ARGS_OK\n\nBAD_ARGS:\n  $P1=new String\n  "
+  proc_body .= "$P1=\"wrong # args: should be \\\""
   proc_body .= name
   proc_body .= " "
   proc_body .= args
-  proc_body .= "\\\"\")\nargs_ok:\n"
+  proc_body .= "\\\"\"\n  .return(1,$P1)\n\nARGS_OK:\n  "
 
   # XXX Is the pop_pad necessary, or would it be  handled as a side
   #  effect of the .return?
@@ -102,12 +160,12 @@ arg_loop_done:
   # a TCL_RETURN (2) from a sub body should be transformed into a TCL_OK (0)
   # to stop propagation outward.  XXX Should use the real constants here
 
-  proc_body .= "($I0,$P0) = interpret(proc_body)\nif $I0 != 2 goto done\n$I0 = 
0\ndone:\npop_pad\ndec call_level\n.return($I0,$P0)\n.end\n"
+  proc_body .= "($I0,$P0) = interpret(proc_body)\n  if $I0 != 2 goto done\n  
$I0 = 0\n  done:\n  pop_pad\n  dec call_level\n  .return($I0,$P0)\n.end\n"
 
   #print "PROC_BODY=\n"
   #print proc_body
   #print "\n--\n"
-  
+
   .local pmc pir_compiler
   pir_compiler = compreg "PIR"
   $P0 = compile pir_compiler, proc_body 

Modified: trunk/languages/tcl/t/cmd_proc.t
==============================================================================
--- trunk/languages/tcl/t/cmd_proc.t    (original)
+++ trunk/languages/tcl/t/cmd_proc.t    Tue Aug  9 07:16:31 2005
@@ -2,9 +2,8 @@
 
 use strict;
 use lib qw(tcl/t t . ../lib ../../lib ../../../lib);
-use Parrot::Test tests => 5;
+use Parrot::Test tests => 9;
 use Test::More;
-use vars qw($SKIP $TODO);
 
 language_output_is("tcl",<<'TCL',<<OUT,"return value");
  set a [proc me {} {
@@ -46,8 +45,35 @@ TCL
 3
 OUT
 
-TODO: {
-local $TODO = "not done yet, but doable";
+language_output_is("tcl",<<'TCL',<<OUT,"too many args");
+ proc me {a b} {
+  puts $a
+  puts $b
+ }
+ me 2 3 4
+TCL
+wrong # args: should be "me a b"
+OUT
+
+language_output_is("tcl",<<'TCL',<<OUT,"too few args");
+ proc me {a b} {
+  puts $a
+  puts $b
+ }
+ me 2
+TCL
+wrong # args: should be "me a b"
+OUT
+
+language_output_is("tcl",<<'TCL',<<OUT,"bad varargs");
+ proc me {a b args} {
+  puts $a
+  puts $b
+ }
+ me 2
+TCL
+wrong # args: should be "me a b args"
+OUT
 
 language_output_is("tcl",<<'TCL',<<OUT,"vararg");
  proc me {a args} {
@@ -59,7 +85,17 @@ TCL
 2
 3 4 5 6
 OUT
-}
+
+language_output_is("tcl",<<'TCL',<<OUT,"vararg empty");
+ proc me {a args} {
+  puts $a
+  puts $args
+ }
+ me 2
+TCL
+2
+
+OUT
 
 __END__
 

Reply via email to