[#1551] Hashes as keys — "Nathaniel Talbott" <nathaniel@...>

I was just playing around with Hash#hash and discovered that you can't use a

13 messages 2003/09/23

|rcr|.xv Index Variables ( *_with_index )

From: "daz" <dooby@...10.karoo.co.uk>
Date: 2003-09-02 14:48:23 UTC
List: ruby-core #1495
Hello 'core,

My first post here, so I'll try not to be too controversial.
It might be too long for busy people.

=begin

  [RCR] proposal - optional block index variable
  ==============================================

* Applies to all iterators, including future additions.

* No new methods.  "with_index" depleted.

* Problem of naming (map_with_indexes/indices) disappears.

* No code breakage.

  "A Language shouldn't get in your way"
* Removes an area where IMO it does.

=end


=begin

Quoting David Black from ruby-talk.org/57500,

  If we had map_with_indices, you could do:
    myarray.map_with_indices {|e,i| e + ", " if i % 2 == 0}.compact

  but we don't.  (Hint, hint.)

End quote.

  myarray.map {|e|.i  e + ", " if i % 2 == 0}.compact
=end


=begin

Private letter to the President of Citizens for MWI, Inc.

  Dear Dr. Black,

  I think the time has arrived for the final push.
  We know where he lives.  We have his photograph ;-/
  All we need now is camping equipment and hot soup.

               Let's violate PoLS !

  Yours faithfully,

  A. Citizen.

=end



=================================================================
Ruby examples:           ruby 1.8.0 (2003-08-30+) [i586-bccwin32]
=================================================================

----------8<-----------------------------------------------------

a = ('a'..'z').to_a
a.map! {|x|.n  ' ' + x + (n+1).to_s if n % 2 == 0}
a.display

#->  a1 c3 e5 g7 i9 k11 m13 o15 q17 s19 u21 w23 y25

----------8<----------------------------------------->8----------

loop {.x
  x < 5 or break
  p x
}

----------8<----------------------------------------->8----------

=begin
 "each_byte_with_index" (etc.) doesn't exist.
=end

'Hello'.each_byte {|ch|.ix puts ch}

#-> 72
#-> 101
#-> 108
#-> 108
#-> 111

----------8<----------------------------------------->8----------

#
#  Until each_with_index gets flushed
#  down the toilet, we could do ...
#
#    each_with_index (with index)           Mmm, sounds nice.

(10..16).each_with_index do |n, wx|.index
  p [n, wx, index]
  raise 'Oh-Oh!' if index != wx
end

#-> [10, 0, 0]
#-> [11, 1, 1]
#-> [12, 2, 2]
#-> [13, 3, 3]
#-> [14, 4, 4]
#-> [15, 5, 5]
#-> [16, 6, 6]

----------8<----------------------------------------->8----------

10.times {|n|.n  n+1}

#-> C:/TEMP/rbA115.TMP:  2: duplicate name for block parameter / index variable
#-> 10.times {|n|.n  n+1}
#->                ^

----------8<----------------------------------------->8----------

y = 10
flg = 'a'
2.times do | z2 |.x
  3.times do | z3 |.y
    puts "  #{z2}#{x}, #{z3}#{y}, (#{flg})"
    if [z2, x, z3, y, flg] == [1,1,1,1,'a']
      flg = 'c'
      puts '* state change *'
      retry  #  retry/redo
    end
    puts '-'*15
  end
end
puts "final y = #{y}"

#->   00, 00, (a)
#-> ---------------
#->   00, 11, (a)
#-> ---------------
#->   00, 22, (a)
#-> ---------------
#->   11, 00, (a)
#-> ---------------
#->   11, 11, (a)
#-> * state change *
#->   11, 00, (c)
#-> ---------------
#->   11, 11, (c)
#-> ---------------
#->   11, 22, (c)
#-> ---------------
#-> final y = 2


=begin
From: http://zem.novylen.net/ruby/withindex.rb

module Enumerable
  def method_missing(meth, *args, &block)
    if meth.to_s =~ /_with_index/
      m = meth.to_s.gsub!('_with_index','')
      i = -1
      self.send(m,*args) {|n|
        i = i+1
        block.call(n,i)
      }
    end
  end
end

=end

=begin
From: http://www.loveruby.net/~aamine/ja/tdiary/20021210.html
#      (extract of translation, edited)

unless [ ].respond_to?(:Sort_by)
  class Array
    def sort_by
      list = [ ]
      each_with_index do |i, idx|
        list.push( [ yield(i), (idx and i) ] )
      end
      list.sort.map { |tmp, (idx and i)| i }
    end
  end
end

# When doing such, the map_with_index
# (or the Iterator) it becomes desired.
#
#(11:49)

=end

----------8<----------------------------------------->8----------

# ============================================================
# Extension for experimentalists  -  $XITER (silly temp. name)
# ============================================================

# You can use $XITER virtual_variable where block_given? applies.
# (Safe anywhere.  Effect will be correct, even if you disagree;)

def x(q)
  3.times do |i|.ix
    printf("\nIter #%i==%i (%i)\n", i, ix, $XITER)
    $XITER += 2
    yield q, i, ix, $XITER
  end
end

x ('roo') do |yq, yi, yix, yiter|.xv
  p [[yq, yi, yix], [yiter, xv], $XITER]
end


#-> Iter #0==0 (0)
#-> [["roo", 0, 0], [2, 2], false]
#->
#-> Iter #1==1 (3)
#-> [["roo", 1, 1], [5, 5], false]
#->
#-> Iter #2==2 (6)
#-> [["roo", 2, 2], [8, 8], false]

----------8<----------------------------------------->8----------

=begin

  Reasons why I left Ruby for another language
  ============================================

  Ruby has powerful iterators but no access to their indexices.
  So I changed to Ruby, which has both!      C OO L.

  Or should that be indicexes ???

  Now my mind is free to explore inject(i) {|a,b|.x 'wheeesh'}



  History (for power readers)
  ===========================

  [CHANGELOG]
  Thu Feb  5 18:58:46 1998  Yukihiro Matsumoto  <matz@netlab.co.jp>

        * enum.c (enum_each_with_index): new method.


  http://www.ruby-talk.org/56121  DAB  - MWI, Inc.
  http://www.ruby-talk.org/56125  Matz - YAGNI
  http://www.ruby-talk.org/56719  Matz
  http://www.ruby-talk.org/56730  Matz
  http://www.ruby-talk.org/56845  _why
  http://www.ruby-talk.org/56939  extending block w/ counter

=end

----------8<----------------------------------------->8----------

# Currently difficult ?

"Hello World!".scan(/[aeiou]./) do |str|.ix
  printf("(%2s) @ %2d\n", str, ix)
end

#-> (el) @  1
#-> (o ) @  4
#-> (or) @  7

----------------------------------------------------->8----------



=================================================================
Implementation Notes
=================================================================
<parse.y>

1) The index variable (xv) is recognised by the parser in a
   similar way to a block parameter.

2) An assignment node is created (L/DASGN) depending on
   whether the xv already exists in an outer scope.

3) When an ITER node is created by the parser and an xv has
   been recognised, pointers to the ASGN node and the ITER
   node are stored in an ITERX node.

   (It would have been easier to extend NODE_ITER by the size
    of a pointer but that could, possibly, extend all ruby
    objects.)

3a) Without xv:        (Normal Ruby)
       NODE_ITER
         u1 'nd_var'   (block params)
         u2 'nd_body'  (block statements)
         u3 'nd_iter'  (func; e.g. each)

3b) With xv:
       NODE_ITERX
         u1 'nd_inode' (-> ITER node)
         u2 'nd_xvasn' (-> L/DASGN)         [would be in u4]
         u3 'nd_iter'  (func; e.g. each)

                  NODE_ITER  (from 'nd_inode' of ITERX above)
                    u1 'nd_var'   (block params)
                    u2 'nd_body'  (block statements)
                    u3  0

=================================================================
<eval.c>

4) When rb_eval sees an ITERX node and the struct BLOCK is
   established,  a pointer to the ASGN node is set in the
   block for easy access and is used in tests for xv presence.
   (Access to the ASGN node via the ITERX node may be lost
    after a ruby 'redo' / 'retry' etc.  Access is maintained
    via the pointer in the BLOCK.)

   [struct BLOCK is necessarily extended by 4 bytes.]

   The value (index count) in the ASGN node is initialised
   to zero at this time.

5) On a yield to the block (rb_yield_0), the value in the
   ASGN node (which also holds the variable's ID) is assigned
   to the index variable.

6) Before rb_yield_0 returns, the index count is incremented
   but will be assigned to the variable only at the start of
   the next iteration.

=================================================================

* Any assignment to the xv from a script will NOT be carried
  over to the next iteration.

* Any iterator method implemented by the interpreter will be
  able to alter the index value before the next iteration.
  For example, String#scan could send the index position of
  each match (currently inaccessible ?) into the block, if
  an xv has been supplied, simply by overwriting the new
  index value before a yield, using ...

   void        rb_xv_assign_long(long);

  String#scan is the only iterator method that has been
  tampered with.  Unmodified, an xv in the block would
  increment from zero like any other but it seemed that
  selected methods might be usefully tweaked ?  (e.g. gsub)

=================================================================




Any need for this ??  (Perhaps in Japan ?)
   (Please pile on the pressure if you need similar fun ;)


 [xv.patch] attached for experiments.   (CVS head 2003/09/02)


(c) Dave Butcher - 2003/09/02  (10:10 +0100)
    attachment is Ruby Licensed


Feel free to criticise but be forewarned that grumbling
about syntax could result in public humiliation from
a prepared, bullet-proof defence (defense) :-)

Thanks:

  Matz             - Ruby
  Nobu             - (for helping poor Win32 users) & speed-patching.
      Ruby Hackers / Library authors.
  PragDave Thomas  - PickAxe & nodeDump & ri & stuff
                      Programming Ruby ...       (K&R === T&H  #-> true)
  PragAndy Hunt    - PickAxe & one-click installer
  Sakazuki-san +   - RDE (Ruby Development Environment)    :(Win32 only)
  Guy Decoux       - 部ude posting & fl/ii (nodedump)
    comp.lang.ruby / ruby-talk regulars.
  David Alan Black - Code-brevity, brick wall head-banging &
                      English language guardianship.


daz

Attachments (1)

xv.patch (10.8 KB, text/x-diff)
diff -u3pPr orig-1.8.0-2003.09.02/eval.c orxv-1.8.0-2003.09.02/eval.c
--- orig-1.8.0-2003.09.02/eval.c	Tue Sep 02 06:52:36 2003
+++ orxv-1.8.0-2003.09.02/eval.c	Tue Sep 02 13:10:30 2003
@@ -106,6 +106,10 @@ static VALUE rb_cUnboundMethod;
 static VALUE umethod_bind _((VALUE, VALUE));
 static VALUE rb_mod_define_method _((int, VALUE*, VALUE));
 
+static VALUE xv_getter _((void));		/* bXV */
+static void  xv_setter _((VALUE));		/* bXV */
+extern void  rb_xv_assign_long _((long));	/* bXV */
+
 static int scope_vmode;
 #define SCOPE_PUBLIC    0
 #define SCOPE_PRIVATE   1
@@ -611,6 +615,7 @@ struct BLOCK {
     VALUE klass;
     NODE *cref;
     int iter;
+    NODE *xvasn;   /* xv ASGN node ptr  bXV */
     int vmode;
     int flags;
     struct RVarmap *dyna_vars;
@@ -639,6 +644,7 @@ static struct BLOCK *ruby_block;
     _block.prev = ruby_block;		\
     _block.outer = ruby_block;		\
     _block.iter = ruby_iter->iter;	\
+    _block.xvasn = 0;	/* bXV */	\
     _block.vmode = scope_vmode;		\
     _block.flags = BLOCK_D_SCOPE;	\
     _block.dyna_vars = ruby_dyna_vars;	\
@@ -2440,6 +2446,7 @@ rb_eval(self, n)
     if (!node) RETURN(Qnil);
 
     ruby_current_node = node;
+
     switch (nd_type(node)) {
       case NODE_BLOCK:
 	if (contnode) {
@@ -2687,6 +2694,7 @@ rb_eval(self, n)
 	result = block_pass(self, node);
 	break;
 
+      case NODE_ITERX:
       case NODE_ITER:
       case NODE_FOR:
 	{
@@ -2697,7 +2705,16 @@ rb_eval(self, n)
 	    if (state == 0) {
 	      iter_retry:
 		PUSH_ITER(ITER_PRE);
-		if (nd_type(node) == NODE_ITER) {
+
+		if (nd_type(node) == NODE_ITERX) {	/* bXV */
+		    ruby_block->var = node->nd_inode->nd_var;
+		    ruby_block->body = node->nd_inode->nd_body;
+		    ruby_block->xvasn = node->nd_xvasn;
+		    ruby_block->xvasn->nd_xvval = INT2FIX(0);  /* bXV Initialize index (zero by convention ;) */
+
+		    result = rb_eval(self, node->nd_iter);
+		}
+		else if (nd_type(node) == NODE_ITER) {
 		    result = rb_eval(self, node->nd_iter);
 		}
 		else {
@@ -3766,6 +3783,7 @@ rb_mod_protected_method_defined(mod, mid
 }
 
 NORETURN(static VALUE terminate_process _((int, const char *, long)));
+
 static VALUE
 terminate_process(status, mesg, mlen)
     int status;
@@ -4081,6 +4099,7 @@ rb_yield_0(val, self, klass, flags, aval
 	ruby_dyna_vars = block->dyna_vars;
     }
     PUSH_CLASS(klass ? klass : block->klass);
+
     if (!klass) {
 	self = block->self;
     }
@@ -4089,6 +4108,7 @@ rb_yield_0(val, self, klass, flags, aval
     if (block->var) {
 	PUSH_TAG(PROT_NONE);
 	if ((state = EXEC_TAG()) == 0) {
+
 	    if (block->var == (NODE*)1) { /* no parameter || */
 		if ((flags & YIELD_PROC_CALL) && RARRAY(val)->len != 0) {
 		    rb_raise(rb_eArgError, "wrong number of arguments (%ld for 0)",
@@ -4140,6 +4160,10 @@ rb_yield_0(val, self, klass, flags, aval
 	if (state) goto pop_state;
     }
 
+    if (block->xvasn) {		/* bXV */
+	assign(0, block->xvasn, block->xvasn->nd_xvval, 0);	/* bXV */
+    }
+
     PUSH_ITER(block->iter);
     PUSH_TAG(PROT_NONE);
     if ((state = EXEC_TAG()) == 0) {
@@ -4209,9 +4233,44 @@ rb_yield_0(val, self, klass, flags, aval
     scope_vmode = old_vmode;
     ruby_current_node = cnode;
     if (state) JUMP_TAG(state);
+
+    if (block->xvasn) {
+	/* bXV - increment index for next iteration */
+	block->xvasn->nd_xvval = INT2FIX((FIX2INT(block->xvasn->nd_xvval))+1);	/* bXV */
+    }
+
     return result;
 }
 
+static VALUE
+xv_getter()		/* bXV */
+{
+    if (rb_block_given_p()) {
+	if (ruby_block->xvasn) {
+	    return ruby_block->xvasn->nd_xvval;
+	}
+    }
+    return Qfalse;
+}
+
+static void
+xv_setter(val)		/* bXV */
+    VALUE val;
+{
+    if (FIXNUM_P(val) && rb_block_given_p()) {
+	if (ruby_block->xvasn) {
+	    ruby_block->xvasn->nd_xvval = val;
+	}
+    }
+}
+
+extern void
+rb_xv_assign_long(val)		/* bXV */
+    long val;
+{
+    xv_setter(INT2FIX(val));
+}
+
 VALUE
 rb_yield(val)
     VALUE val;
@@ -6527,6 +6586,7 @@ Init_eval()
 
     rb_define_virtual_variable("$@", errat_getter, errat_setter);
     rb_define_hooked_variable("$!", &ruby_errinfo, 0, errinfo_setter);
+    rb_define_virtual_variable("$XITER", xv_getter, xv_setter);		/* bXV */
 
     rb_define_global_function("eval", rb_f_eval, -1);
     rb_define_global_function("iterator?", rb_f_block_given_p, 0);
diff -u3pPr orig-1.8.0-2003.09.02/gc.c orxv-1.8.0-2003.09.02/gc.c
--- orig-1.8.0-2003.09.02/gc.c	Fri Aug 22 09:09:56 2003
+++ orxv-1.8.0-2003.09.02/gc.c	Mon Sep 01 08:26:20 2003
@@ -675,6 +675,7 @@ rb_gc_mark_children(ptr)
 	  case NODE_IF:		/* 1,2,3 */
 	  case NODE_FOR:
 	  case NODE_ITER:
+	  case NODE_ITERX:		/* bXV */
 	  case NODE_CREF:
 	  case NODE_WHEN:
 	  case NODE_MASGN:
diff -u3pPr orig-1.8.0-2003.09.02/node.h orxv-1.8.0-2003.09.02/node.h
--- orig-1.8.0-2003.09.02/node.h	Wed Aug 27 20:43:46 2003
+++ orxv-1.8.0-2003.09.02/node.h	Tue Sep 02 01:26:18 2003
@@ -29,6 +29,7 @@ enum node_type {
     NODE_OPT_N,
     NODE_WHILE,
     NODE_UNTIL,
+    NODE_ITERX,
     NODE_ITER,
     NODE_FOR,
     NODE_BREAK,
@@ -194,6 +195,11 @@ typedef struct RNode {
 #define nd_ibdy  u2.node
 #define nd_iter  u3.node
 
+#define nd_inode u1.node  /* bXV -> NODE_ITER  */
+#define nd_xvasn u2.node  /* bXV -> NODE_?ASGN */
+
+#define nd_xvval u2.value /* bXV index value   */
+
 #define nd_value u2.node
 #define nd_aid   u3.id
 
@@ -252,6 +258,7 @@ typedef struct RNode {
 #define NEW_UNTIL(c,b,n) NEW_NODE(NODE_UNTIL,c,b,n)
 #define NEW_FOR(v,i,b) NEW_NODE(NODE_FOR,v,b,i)
 #define NEW_ITER(v,i,b) NEW_NODE(NODE_ITER,v,b,i)
+#define NEW_ITERX(inode,xvasn) NEW_NODE(NODE_ITERX,inode,xvasn,0)
 #define NEW_BREAK(s) NEW_NODE(NODE_BREAK,s,0,0)
 #define NEW_NEXT(s) NEW_NODE(NODE_NEXT,s,0,0)
 #define NEW_REDO() NEW_NODE(NODE_REDO,0,0,0)
diff -u3pPr orig-1.8.0-2003.09.02/parse.y orxv-1.8.0-2003.09.02/parse.y
--- orig-1.8.0-2003.09.02/parse.y	Tue Sep 02 06:50:46 2003
+++ orxv-1.8.0-2003.09.02/parse.y	Tue Sep 02 11:13:12 2003
@@ -61,6 +61,8 @@ NODE *ruby_eval_tree = 0;
 char *ruby_sourcefile;		/* current source file */
 int   ruby_sourceline;		/* current line no. */
 
+int   xv_line;			/* bXV line no. */
+
 static int yylex();
 static int yyerror();
 
@@ -260,6 +262,7 @@ static void top_local_setup();
 %type <node> f_arglist f_args f_optarg f_opt f_block_arg opt_f_block_arg
 %type <node> assoc_list assocs assoc undef_list backref string_dvar
 %type <node> block_var opt_block_var brace_block cmd_brace_block do_block lhs none
+%type <node> opt_block_index  var_index  paren_var_index  /* bXV */
 %type <node> mlhs mlhs_head mlhs_basic mlhs_entry mlhs_item mlhs_node
 %type <id>   fitem variable sym symbol operation operation2 operation3
 %type <id>   cname fname op f_rest_arg
@@ -651,13 +654,15 @@ block_command	: block_call
 cmd_brace_block	: tLBRACE_ARG
 		    {
 			$<vars>$ = dyna_push();
-			$<num>1 = ruby_sourceline;
+			$<num>1 = xv_line = ruby_sourceline;
 		    }
-		  opt_block_var {$<vars>$ = ruby_dyna_vars;}
+		  opt_block_var   {$<vars>$ = ruby_dyna_vars; xv_line = ruby_sourceline;}	/* bXV */
+		  opt_block_index {$<vars>4 = ruby_dyna_vars;}					/* bXV */
 		  compstmt
 		  '}'
 		    {
-			$$ = NEW_ITER($3, 0, dyna_init($5, $<vars>4));
+			$$ = NEW_ITER($3, 0, dyna_init($7, $<vars>4));
+			if ($5) $$ = NEW_ITERX($$, $5);			/* bXV */
 			nd_set_line($$, $<num>1);
 			dyna_pop($<vars>2);
 		    }
@@ -1733,16 +1738,44 @@ opt_block_var	: none
 		    }
 		;
 
+paren_var_index	: '(' /* none */ ')'
+		    {
+			$$ = 0;
+		    }
+		| '(' var_index ')'
+		    {
+			$$ = $2;
+		    }
+		;
+
+opt_block_index	: none
+		| '.'  var_index
+		    {
+			if (xv_line != ruby_sourceline) goto xv_Err_lbfd;
+			$$ = $2;
+		    }
+		| '.'  paren_var_index
+		    {
+			if (xv_line != ruby_sourceline) {
+		     xv_Err_lbfd:
+			    rb_warn("break in line %i", xv_line);
+			}
+			$$ = $2;
+		    }
+		;
+
 do_block	: kDO_BLOCK
 		    {
 		        $<vars>$ = dyna_push();
-			$<num>1 = ruby_sourceline;
+			$<num>1 = xv_line = ruby_sourceline;
 		    }
-		  opt_block_var {$<vars>$ = ruby_dyna_vars;}
+		  opt_block_var   {$<vars>$ = ruby_dyna_vars; xv_line = ruby_sourceline;}	/* bXV */
+		  opt_block_index {$<vars>4 = ruby_dyna_vars;}					/* bXV */
 		  compstmt
 		  kEND
 		    {
-			$$ = NEW_ITER($3, 0, dyna_init($5, $<vars>4));
+			$$ = NEW_ITER($3, 0, dyna_init($7, $<vars>4));
+			if ($5) $$ = NEW_ITERX($$, $5);			/* bXV */
 			nd_set_line($$, $<num>1);
 			dyna_pop($<vars>2);
 		    }
@@ -1799,24 +1832,28 @@ method_call	: operation paren_args
 brace_block	: '{'
 		    {
 		        $<vars>$ = dyna_push();
-			$<num>1 = ruby_sourceline;
+			$<num>1 = xv_line = ruby_sourceline;
 		    }
-		  opt_block_var {$<vars>$ = ruby_dyna_vars;}
+		  opt_block_var   {$<vars>$ = ruby_dyna_vars; xv_line = ruby_sourceline;}	/* bXV */
+		  opt_block_index {$<vars>4 = ruby_dyna_vars;}					/* bXV */
 		  compstmt '}'
 		    {
-			$$ = NEW_ITER($3, 0, dyna_init($5, $<vars>4));
+			$$ = NEW_ITER($3, 0, dyna_init($7, $<vars>4));
+			if ($5) $$ = NEW_ITERX($$, $5);			/* bXV */
 			nd_set_line($$, $<num>1);
 			dyna_pop($<vars>2);
 		    }
 		| kDO
 		    {
 		        $<vars>$ = dyna_push();
-			$<num>1 = ruby_sourceline;
+			$<num>1 = xv_line = ruby_sourceline;
 		    }
-		  opt_block_var {$<vars>$ = ruby_dyna_vars;}
+		  opt_block_var   {$<vars>$ = ruby_dyna_vars; xv_line = ruby_sourceline;}	/* bXV */
+		  opt_block_index {$<vars>4 = ruby_dyna_vars;}					/* bXV */
 		  compstmt kEND
 		    {
-			$$ = NEW_ITER($3, 0, dyna_init($5, $<vars>4));
+			$$ = NEW_ITER($3, 0, dyna_init($7, $<vars>4));
+			if ($5) $$ = NEW_ITERX($$, $5);			/* bXV */
 			nd_set_line($$, $<num>1);
 			dyna_pop($<vars>2);
 		    }
@@ -2160,6 +2197,33 @@ var_lhs		: variable
 		    }
 		;
 
+var_index	: tCONSTANT	{ goto xv_Err_bimbl; }
+		| tIVAR		{ goto xv_Err_bimbl; }
+		| tGVAR		{ goto xv_Err_bimbl; }
+		| tCVAR		{ goto xv_Err_bimbl; }
+		| tIDENTIFIER
+		    {
+			if (!is_local_id($1)) {
+		    xv_Err_bimbl:
+			    yyerror("block index must be a local variable");
+			}
+			if (rb_dvar_curr($1)) {
+			    yyerror("duplicate name for block parameter / index variable");
+			}
+
+			if (rb_dvar_defined($1)) {
+			    $$ = NEW_DASGN($1, 0);
+			}
+			else if (local_id($1) || !dyna_in_block()) {
+			    $$ = NEW_LASGN($1, 0);
+			}
+			else{
+			    rb_dvar_push($1, 0);
+			    $$ = NEW_DASGN_CURR($1, 0);
+			}
+		    }
+		;
+
 backref		: tNTH_REF
 		| tBACK_REF
 		;
@@ -2541,6 +2605,7 @@ yycompile(f, line)
     n = yyparse();
     ruby_debug_lines = 0;
     compile_for_eval = 0;
+
     ruby_in_compile = 0;
     cond_stack = 0;
     cmdarg_stack = 0;
diff -u3pPr orig-1.8.0-2003.09.02/string.c orxv-1.8.0-2003.09.02/string.c
--- orig-1.8.0-2003.09.02/string.c	Wed Aug 27 20:43:46 2003
+++ orxv-1.8.0-2003.09.02/string.c	Sat Aug 30 20:38:30 2003
@@ -3066,6 +3066,7 @@ rb_str_scan(str, pat)
     while (!NIL_P(result = scan_once(str, pat, &start))) {
 	match = rb_backref_get();
 	rb_match_busy(match);
+	rb_xv_assign_long(start - RSTRING(result)->len);		/* bXV trick */
 	rb_yield(result);
 	rb_backref_set(match);	/* restore $~ value */
     }

In This Thread

Prev Next