1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* parse.y (gettable_gen): warns if VCALL name is used as

out-of-scope block local variable.  [EXPERIMENTAL]

* parse.y (opt_bv_decl): add explicit block local variable
  declaration.  raises error for name conflicts.  [EXPERIMENTAL]


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8128 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 2005-03-09 09:29:52 +00:00
parent 9ef561b6e0
commit f43cae2b05
8 changed files with 265 additions and 37 deletions

View file

@ -1,3 +1,11 @@
Wed Mar 9 18:09:51 2005 Yukihiro Matsumoto <matz@ruby-lang.org>
* parse.y (gettable_gen): warns if VCALL name is used as
out-of-scope block local variable. [EXPERIMENTAL]
* parse.y (opt_bv_decl): add explicit block local variable
declaration. raises error for name conflicts. [EXPERIMENTAL]
Wed Mar 9 13:37:57 2005 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp> Wed Mar 9 13:37:57 2005 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/sample/tktextio.rb: fix bug of handling 'end' position. * ext/tk/sample/tktextio.rb: fix bug of handling 'end' position.
@ -14,6 +22,12 @@ Tue Mar 8 13:39:25 2005 NAKAMURA Usaku <usa@ruby-lang.org>
* ext/socket/mkconstants.rb: workaround for some of 4.4BSD-Lite * ext/socket/mkconstants.rb: workaround for some of 4.4BSD-Lite
derived OSs. derived OSs.
Tue Mar 8 12:36:17 2005 Yukihiro Matsumoto <matz@ruby-lang.org>
* ext/socket/socket.c: document from Sam Roberts
<sroberts@uniserve.com> for getsockopt and setsockopt is merged.
[ruby-doc:824]
Tue Mar 8 10:48:53 2005 NAKAMURA Usaku <usa@ruby-lang.org> Tue Mar 8 10:48:53 2005 NAKAMURA Usaku <usa@ruby-lang.org>
* eval.c (rb_exec_recursive): declaration should precede statements * eval.c (rb_exec_recursive): declaration should precede statements

View file

@ -271,6 +271,51 @@ bsock_close_write(sock)
return Qnil; return Qnil;
} }
/*
* Document-method: setsockopt
* call-seq: setsockopt(level, optname, optval)
*
* Sets a socket option. These are protocol and system specific, see your
* local sytem documentation for details.
*
* === Parameters
* * +level+ is an integer, usually one of the SOL_ constants such as
* Socket::SOL_SOCKET, or a protocol level.
* * +optname+ is an integer, usually one of the SO_ constants, such
* as Socket::SO_REUSEADDR.
* * +optval+ is the value of the option, it is passed to the underlying
* setsockopt() as a pointer to a certain number of bytes. How this is
* done depends on the type:
* - Fixnum: value is assigned to an int, and a pointer to the int is
* passed, with length of sizeof(int).
* - true or false: 1 or 0 (respectively) is assigned to an int, and the
* int is passed as for a Fixnum. Note that +false+ must be passed,
* not +nil+.
* - String: the string's data and length is passed to the socket.
*
* === Examples
*
* Some socket options are integers with boolean values, in this case
* #setsockopt could be called like this:
* sock.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
*
* Some socket options are integers with numeric values, in this case
* #setsockopt could be called like this:
* sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, 255)
*
* Option values may be structs. Passing them can be complex as it involves
* examining your system headers to determine the correct definition. An
* example is an +ip_mreq+, which may be defined in your system headers as:
* struct ip_mreq {
* struct in_addr imr_multiaddr;
* struct in_addr imr_interface;
* };
*
* In this case #setsockopt could be called like this:
* optval = IPAddr.new("224.0.0.251") + Socket::INADDR_ANY
* sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, optval)
*
*/
static VALUE static VALUE
bsock_setsockopt(sock, lev, optname, val) bsock_setsockopt(sock, lev, optname, val)
VALUE sock, lev, optname, val; VALUE sock, lev, optname, val;
@ -311,6 +356,46 @@ bsock_setsockopt(sock, lev, optname, val)
return INT2FIX(0); return INT2FIX(0);
} }
/*
* Document-method: getsockopt
* call-seq: getsockopt(level, optname)
*
* Gets a socket option. These are protocol and system specific, see your
* local sytem documentation for details. The option is returned as
* a String with the data being the binary value of the socket option.
*
* === Parameters
* * +level+ is an integer, usually one of the SOL_ constants such as
* Socket::SOL_SOCKET, or a protocol level.
* * +optname+ is an integer, usually one of the SO_ constants, such
* as Socket::SO_REUSEADDR.
*
* === Examples
*
* Some socket options are integers with boolean values, in this case
* #getsockopt could be called like this:
* optval = sock.getsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR)
* optval = optval.unpack "i"
* reuseaddr = optval[0] == 0 ? false : true
*
* Some socket options are integers with numeric values, in this case
* #getsockopt could be called like this:
* optval = sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL)
* ipttl = optval.unpack("i")[0]
*
* Option values may be structs. Decoding them can be complex as it involves
* examining your system headers to determine the correct definition. An
* example is a +struct linger+, which may be defined in your system headers
* as:
* struct linger {
* int l_onoff;
* int l_linger;
* };
*
* In this case #getsockopt could be called like this:
* optval = sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER)
* onoff, linger = optval.unpack "ii"
*/
static VALUE static VALUE
bsock_getsockopt(sock, lev, optname) bsock_getsockopt(sock, lev, optname)
VALUE sock, lev, optname; VALUE sock, lev, optname;

View file

@ -1667,8 +1667,8 @@ else
pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1)
v.command(proc{|*args| c.yview(*args)}) v.command(proc{|*args| f.yview(*args)})
h.command(proc{|*args| c.xview(*args)}) h.command(proc{|*args| f.xview(*args)})
} }
end end

View file

@ -1667,8 +1667,8 @@ else
pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1)
v.command(proc{|*args| c.yview(*args)}) v.command(proc{|*args| f.yview(*args)})
h.command(proc{|*args| c.xview(*args)}) h.command(proc{|*args| f.xview(*args)})
} }
end end

View file

@ -1664,8 +1664,8 @@ else
pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1)
v.command(proc{|*args| c.yview(*args)}) v.command(proc{|*args| f.yview(*args)})
h.command(proc{|*args| c.xview(*args)}) h.command(proc{|*args| f.xview(*args)})
} }
end end

View file

@ -1664,8 +1664,8 @@ else
pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1)
v.command(proc{|*args| c.yview(*args)}) v.command(proc{|*args| f.yview(*args)})
h.command(proc{|*args| c.xview(*args)}) h.command(proc{|*args| f.xview(*args)})
} }
end end

185
parse.y
View file

@ -103,6 +103,8 @@ struct local_vars {
int nofree; int nofree;
int cnt; int cnt;
int dlev; int dlev;
int dname_size;
ID *dnames;
struct RVarmap* dyna_vars; struct RVarmap* dyna_vars;
struct local_vars *prev; struct local_vars *prev;
}; };
@ -251,6 +253,8 @@ static NODE *gettable_gen _((struct parser_params*,ID));
#define gettable(id) gettable_gen(parser,id) #define gettable(id) gettable_gen(parser,id)
static NODE *assignable_gen _((struct parser_params*,ID,NODE*)); static NODE *assignable_gen _((struct parser_params*,ID,NODE*));
#define assignable(id,node) assignable_gen(parser, id, node) #define assignable(id,node) assignable_gen(parser, id, node)
static NODE *new_bv_gen _((struct parser_params*,ID,NODE*));
#define new_bv(id,node) new_bv_gen(parser, id, node)
static NODE *aryset_gen _((struct parser_params*,NODE*,NODE*)); static NODE *aryset_gen _((struct parser_params*,NODE*,NODE*));
#define aryset(node1,node2) aryset_gen(parser, node1, node2) #define aryset(node1,node2) aryset_gen(parser, node1, node2)
static NODE *attrset_gen _((struct parser_params*,NODE*,ID)); static NODE *attrset_gen _((struct parser_params*,NODE*,ID));
@ -285,6 +289,10 @@ static int dyna_in_block_gen _((struct parser_params*));
#define dyna_in_block() dyna_in_block_gen(parser) #define dyna_in_block() dyna_in_block_gen(parser)
static NODE *dyna_init_gen _((struct parser_params*, NODE*, struct RVarmap *)); static NODE *dyna_init_gen _((struct parser_params*, NODE*, struct RVarmap *));
#define dyna_init(node, pre) dyna_init_gen(parser, node, pre) #define dyna_init(node, pre) dyna_init_gen(parser, node, pre)
static void dyna_var_gen _((struct parser_params*,ID));
#define dyna_var(id) dyna_var_gen(parser, id)
static void dyna_check_gen _((struct parser_params*,ID));
#define dyna_check(id) dyna_check_gen(parser, id)
static void top_local_init_gen _((struct parser_params*)); static void top_local_init_gen _((struct parser_params*));
#define top_local_init() top_local_init_gen(parser) #define top_local_init() top_local_init_gen(parser)
@ -365,6 +373,8 @@ static VALUE ripper_id2sym _((ID));
#define method_arg(m,a) dispatch2(method_add_arg,m,a) #define method_arg(m,a) dispatch2(method_add_arg,m,a)
#define escape_Qundef(x) ((x)==Qundef ? Qnil : (x)) #define escape_Qundef(x) ((x)==Qundef ? Qnil : (x))
#define FIXME 0
#endif /* RIPPER */ #endif /* RIPPER */
#ifndef RIPPER #ifndef RIPPER
@ -492,7 +502,8 @@ static void ripper_compile_error _((struct parser_params*, const char *fmt, ...)
%type <node> mrhs superclass block_call block_command %type <node> mrhs superclass block_call block_command
%type <node> f_arglist f_args f_optarg f_opt f_block_arg opt_f_block_arg %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> assoc_list assocs assoc undef_list backref string_dvar
%type <node> for_var block_var opt_block_var block_var_def block_par %type <node> for_var block_var opt_block_var block_var_def block_param
%type <node> opt_bv_decl bv_decls bv_decl
%type <node> brace_block cmd_brace_block do_block lhs none fitem %type <node> brace_block cmd_brace_block do_block lhs none fitem
%type <node> mlhs mlhs_head mlhs_basic mlhs_entry mlhs_item mlhs_node %type <node> mlhs mlhs_head mlhs_basic mlhs_entry mlhs_item mlhs_node
%type <id> fsym variable sym symbol operation operation2 operation3 %type <id> fsym variable sym symbol operation operation2 operation3
@ -1098,7 +1109,9 @@ cmd_brace_block : tLBRACE_ARG
'}' '}'
{ {
/*%%%*/ /*%%%*/
$$ = NEW_ITER($3, 0, dyna_init($5, $<vars>4)); $3->nd_body = block_append($3->nd_body,
dyna_init($5, $<vars>4));
$$ = $3;
nd_set_line($$, $<num>1); nd_set_line($$, $<num>1);
dyna_pop($<vars>2); dyna_pop($<vars>2);
/*% /*%
@ -2963,7 +2976,7 @@ for_var : lhs
| mlhs | mlhs
; ;
block_par : mlhs_item block_param : mlhs_item
{ {
/*%%%*/ /*%%%*/
$$ = NEW_LIST($1); $$ = NEW_LIST($1);
@ -2971,7 +2984,7 @@ block_par : mlhs_item
$$ = mlhs_add(mlhs_new(), $1); $$ = mlhs_add(mlhs_new(), $1);
%*/ %*/
} }
| block_par ',' mlhs_item | block_param ',' mlhs_item
{ {
/*%%%*/ /*%%%*/
$$ = list_append($1, $3); $$ = list_append($1, $3);
@ -2981,7 +2994,7 @@ block_par : mlhs_item
} }
; ;
block_var : block_par block_var : block_param
{ {
/*%%%*/ /*%%%*/
if ($1->nd_alen == 1) { if ($1->nd_alen == 1) {
@ -2995,7 +3008,7 @@ block_var : block_par
$$ = blockvar_new($1); $$ = blockvar_new($1);
%*/ %*/
} }
| block_par ',' | block_param ','
{ {
/*%%%*/ /*%%%*/
$$ = NEW_MASGN($1, 0); $$ = NEW_MASGN($1, 0);
@ -3003,7 +3016,7 @@ block_var : block_par
$$ = blockvar_new($1); $$ = blockvar_new($1);
%*/ %*/
} }
| block_par ',' tAMPER lhs | block_param ',' tAMPER lhs
{ {
/*%%%*/ /*%%%*/
$$ = NEW_BLOCK_VAR($4, NEW_MASGN($1, 0)); $$ = NEW_BLOCK_VAR($4, NEW_MASGN($1, 0));
@ -3011,7 +3024,7 @@ block_var : block_par
$$ = blockvar_add_block(blockvar_new($1), $4); $$ = blockvar_add_block(blockvar_new($1), $4);
%*/ %*/
} }
| block_par ',' tSTAR lhs ',' tAMPER lhs | block_param ',' tSTAR lhs ',' tAMPER lhs
{ {
/*%%%*/ /*%%%*/
$$ = NEW_BLOCK_VAR($7, NEW_MASGN($1, $4)); $$ = NEW_BLOCK_VAR($7, NEW_MASGN($1, $4));
@ -3020,7 +3033,7 @@ block_var : block_par
$$ = blockvar_add_block($$, $7); $$ = blockvar_add_block($$, $7);
%*/ %*/
} }
| block_par ',' tSTAR ',' tAMPER lhs | block_param ',' tSTAR ',' tAMPER lhs
{ {
/*%%%*/ /*%%%*/
$$ = NEW_BLOCK_VAR($6, NEW_MASGN($1, -1)); $$ = NEW_BLOCK_VAR($6, NEW_MASGN($1, -1));
@ -3029,7 +3042,7 @@ block_var : block_par
$$ = blockvar_add_block($$, $6); $$ = blockvar_add_block($$, $6);
%*/ %*/
} }
| block_par ',' tSTAR lhs | block_param ',' tSTAR lhs
{ {
/*%%%*/ /*%%%*/
$$ = NEW_MASGN($1, $4); $$ = NEW_MASGN($1, $4);
@ -3037,7 +3050,7 @@ block_var : block_par
$$ = blockvar_add_star(blockvar_new($1), $4); $$ = blockvar_add_star(blockvar_new($1), $4);
%*/ %*/
} }
| block_par ',' tSTAR | block_param ',' tSTAR
{ {
/*%%%*/ /*%%%*/
$$ = NEW_MASGN($1, -1); $$ = NEW_MASGN($1, -1);
@ -3090,34 +3103,85 @@ block_var : block_par
; ;
opt_block_var : none opt_block_var : none
| block_var_def
{
$$ = $1;
}
;
block_var_def : '|' /* none */ '|'
{ {
/*%%%*/ /*%%%*/
$$ = (NODE*)1; $$ = NEW_ITER(0, 0, 0);
/*% /*%
$$ = dispatch1(blockvar_new, mlhs_new()); %*/
}
| block_var_def
;
block_var_def : '|' opt_bv_decl '|'
{
/*%%%*/
$$ = NEW_ITER((NODE*)1, 0, $2);
/*%
$$ = blockvar_new(mlhs_new());
%*/ %*/
} }
| tOROP | tOROP
{ {
/*%%%*/ /*%%%*/
$$ = (NODE*)1; $$ = NEW_ITER((NODE*)1, 0, 0);
/*% /*%
$$ = dispatch1(blockvar_new, mlhs_new()); $$ = blockvar_new(mlhs_new());
%*/ %*/
} }
| '|' block_var '|' | '|' block_var opt_bv_decl '|'
{
/*%%%*/
$$ = NEW_ITER($2, 0, $3);
/*%
$$ = blockvar_new($2);
%*/
}
;
opt_bv_decl : none
| ';' bv_decls
{ {
/*%%%*/ /*%%%*/
$$ = $2; $$ = $2;
/*% /*%
$$ = dispatch1(blockvar_new, $2); $$ = FIXME;
%*/
}
;
bv_decls : bv_decl
{
/*%%%*/
$$ = $1;
/*%
$$ = FIXME;
%*/
}
| bv_decls ',' bv_decl
{
/*%%%*/
$$ = block_append($1, $3);
/*%
$$ = FIXME;
%*/
}
;
bv_decl : tIDENTIFIER
{
/*%%%*/
$$ = new_bv($1, NEW_NIL());
/*%
$$ = FIXME;
%*/
}
| tIDENTIFIER '=' primary
{
/*%%%*/
$$ = new_bv($1, $3);
/*%
$$ = FIXME;
%*/ %*/
} }
; ;
@ -3139,7 +3203,9 @@ do_block : kDO_BLOCK
kEND kEND
{ {
/*%%%*/ /*%%%*/
$$ = NEW_ITER($3, 0, dyna_init($5, $<vars>4)); $3->nd_body = block_append($3->nd_body,
dyna_init($5, $<vars>4));
$$ = $3;
nd_set_line($$, $<num>1); nd_set_line($$, $<num>1);
dyna_pop($<vars>2); dyna_pop($<vars>2);
/*% /*%
@ -3253,7 +3319,9 @@ brace_block : '{'
compstmt '}' compstmt '}'
{ {
/*%%%*/ /*%%%*/
$$ = NEW_ITER($3, 0, dyna_init($5, $<vars>4)); $3->nd_body = block_append($3->nd_body,
dyna_init($5, $<vars>4));
$$ = $3;
nd_set_line($$, $<num>1); nd_set_line($$, $<num>1);
dyna_pop($<vars>2); dyna_pop($<vars>2);
/*% /*%
@ -3277,7 +3345,9 @@ brace_block : '{'
compstmt kEND compstmt kEND
{ {
/*%%%*/ /*%%%*/
$$ = NEW_ITER($3, 0, dyna_init($5, $<vars>4)); $3->nd_body = block_append($3->nd_body,
dyna_init($5, $<vars>4));
$$ = $3;
nd_set_line($$, $<num>1); nd_set_line($$, $<num>1);
dyna_pop($<vars>2); dyna_pop($<vars>2);
/*% /*%
@ -6831,6 +6901,7 @@ gettable_gen(parser, id)
if (dyna_in_block() && rb_dvar_defined(id)) return NEW_DVAR(id); if (dyna_in_block() && rb_dvar_defined(id)) return NEW_DVAR(id);
if (local_id(id)) return NEW_LVAR(id); if (local_id(id)) return NEW_LVAR(id);
/* method call without arguments */ /* method call without arguments */
dyna_check(id);
return NEW_VCALL(id); return NEW_VCALL(id);
} }
else if (is_global_id(id)) { else if (is_global_id(id)) {
@ -6885,7 +6956,7 @@ assignable_gen(parser, id, val)
return NEW_LASGN(id, val); return NEW_LASGN(id, val);
} }
else{ else{
rb_dvar_push(id, Qnil); dyna_var(id);
return NEW_DASGN_CURR(id, val); return NEW_DASGN_CURR(id, val);
} }
} }
@ -6910,6 +6981,22 @@ assignable_gen(parser, id, val)
return 0; return 0;
} }
static NODE*
new_bv_gen(parser, name, val)
struct parser_params *parser;
ID name;
NODE *val;
{
if (is_local_id(name) && !rb_dvar_defined(name) && !local_id(name)) {
dyna_var(name);
return NEW_DASGN_CURR(name, val);
}
else {
compile_error(PARSER_ARG "local variable name conflict - %s",
rb_id2name(name));
return 0;
}
}
static NODE * static NODE *
aryset_gen(parser, recv, idx) aryset_gen(parser, recv, idx)
struct parser_params *parser; struct parser_params *parser;
@ -7629,6 +7716,8 @@ local_push_gen(parser, top)
local->cnt = 0; local->cnt = 0;
local->tbl = 0; local->tbl = 0;
local->dlev = 0; local->dlev = 0;
local->dname_size = 0;
local->dnames = 0;
local->dyna_vars = ruby_dyna_vars; local->dyna_vars = ruby_dyna_vars;
lvtbl = local; lvtbl = local;
if (!top) { if (!top) {
@ -7648,6 +7737,9 @@ local_pop_gen(parser)
if (!lvtbl->nofree) xfree(lvtbl->tbl); if (!lvtbl->nofree) xfree(lvtbl->tbl);
else lvtbl->tbl[0] = lvtbl->cnt; else lvtbl->tbl[0] = lvtbl->cnt;
} }
if (lvtbl->dnames) {
xfree(lvtbl->dnames);
}
ruby_dyna_vars = lvtbl->dyna_vars; ruby_dyna_vars = lvtbl->dyna_vars;
xfree(lvtbl); xfree(lvtbl);
lvtbl = local; lvtbl = local;
@ -7772,6 +7864,42 @@ top_local_setup_gen(parser)
local_pop(); local_pop();
} }
static void
dyna_var_gen(parser, id)
struct parser_params *parser;
ID id;
{
int i;
rb_dvar_push(id, Qnil);
for (i=0; i<lvtbl->dname_size; i++) {
if (lvtbl->dnames[i] == id) return;
}
if (lvtbl->dname_size == 0) {
lvtbl->dnames = ALLOC_N(ID, 1);
}
else {
REALLOC_N(lvtbl->dnames, ID, lvtbl->dname_size+1);
}
lvtbl->dnames[lvtbl->dname_size++] = id;
}
static void
dyna_check_gen(parser, id)
struct parser_params *parser;
ID id;
{
int i;
if (in_defined) return; /* no check needed */
for (i=0; i<lvtbl->dname_size; i++) {
if (lvtbl->dnames[i] == id) {
rb_warnS("out-of-scope variable - %s", rb_id2name(id));
return;
}
}
}
static struct RVarmap* static struct RVarmap*
dyna_push_gen(parser) dyna_push_gen(parser)
struct parser_params *parser; struct parser_params *parser;
@ -8819,3 +8947,4 @@ Init_ripper()
rb_intern("&&"); rb_intern("&&");
} }
#endif /* RIPPER */ #endif /* RIPPER */

2
re.c
View file

@ -1719,7 +1719,7 @@ rb_reg_match_m(argc, argv, re)
* options are propagated, and new options may not be specified (a change as of * options are propagated, and new options may not be specified (a change as of
* Ruby 1.8). If <i>options</i> is a <code>Fixnum</code>, it should be one or * Ruby 1.8). If <i>options</i> is a <code>Fixnum</code>, it should be one or
* more of the constants <code>Regexp::EXTENDED</code>, * more of the constants <code>Regexp::EXTENDED</code>,
* <code>Regexp::IGNORECASE</code>, and <code>Regexp::POSIXLINE</code>, * <code>Regexp::IGNORECASE</code>, and <code>Regexp::MULTILINE</code>,
* <em>or</em>-ed together. Otherwise, if <i>options</i> is not * <em>or</em>-ed together. Otherwise, if <i>options</i> is not
* <code>nil</code>, the regexp will be case insensitive. The <i>lang</i> * <code>nil</code>, the regexp will be case insensitive. The <i>lang</i>
* parameter enables multibyte support for the regexp: `n', `N' = none, `e', * parameter enables multibyte support for the regexp: `n', `N' = none, `e',