зеркало из https://github.com/github/ruby.git
Numbered parameters [Feature #4475]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67278 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
0fa4a6a618
Коммит
12acc751e3
3
NEWS
3
NEWS
|
@ -25,6 +25,9 @@ sufficient information, see the ChangeLog file or Redmine
|
||||||
* Non-Symbol keys in a keyword arguments hash was prohibited at 2.6.0, but
|
* Non-Symbol keys in a keyword arguments hash was prohibited at 2.6.0, but
|
||||||
now allowed again. [Bug #15658]
|
now allowed again. [Bug #15658]
|
||||||
|
|
||||||
|
* Numbered parameter as the default block parameter is introduced as an
|
||||||
|
experimental feature. [Feature #4475]
|
||||||
|
|
||||||
=== Core classes updates (outstanding ones only)
|
=== Core classes updates (outstanding ones only)
|
||||||
|
|
||||||
Enumerable::
|
Enumerable::
|
||||||
|
|
|
@ -532,7 +532,7 @@ end
|
||||||
assert_syntax_error "unterminated string meets end of file", '().."', '[ruby-dev:29732]'
|
assert_syntax_error "unterminated string meets end of file", '().."', '[ruby-dev:29732]'
|
||||||
assert_equal %q{[]}, %q{$&;[]}, '[ruby-dev:31068]'
|
assert_equal %q{[]}, %q{$&;[]}, '[ruby-dev:31068]'
|
||||||
assert_syntax_error "syntax error, unexpected *, expecting '}'", %q{{*0}}, '[ruby-dev:31072]'
|
assert_syntax_error "syntax error, unexpected *, expecting '}'", %q{{*0}}, '[ruby-dev:31072]'
|
||||||
assert_syntax_error "`@0' is not allowed as an instance variable name", %q{@0..0}, '[ruby-dev:31095]'
|
assert_syntax_error "leading zero is not allowed as a numbered parameter", %q{@0..0}, '[ruby-dev:31095]'
|
||||||
assert_syntax_error "identifier $00 is not valid to get", %q{$00..0}, '[ruby-dev:31100]'
|
assert_syntax_error "identifier $00 is not valid to get", %q{$00..0}, '[ruby-dev:31100]'
|
||||||
assert_syntax_error "identifier $00 is not valid to set", %q{0..$00=1}
|
assert_syntax_error "identifier $00 is not valid to set", %q{0..$00=1}
|
||||||
assert_equal %q{0}, %q{[*0];0}, '[ruby-dev:31102]'
|
assert_equal %q{0}, %q{[*0];0}, '[ruby-dev:31102]'
|
||||||
|
|
|
@ -51,6 +51,7 @@ typedef struct {
|
||||||
ID ripper_id_label_end;
|
ID ripper_id_label_end;
|
||||||
ID ripper_id_tlambda;
|
ID ripper_id_tlambda;
|
||||||
ID ripper_id_tlambeg;
|
ID ripper_id_tlambeg;
|
||||||
|
ID ripper_id_tnumparam;
|
||||||
|
|
||||||
ID ripper_id_ignored_nl;
|
ID ripper_id_ignored_nl;
|
||||||
ID ripper_id_comment;
|
ID ripper_id_comment;
|
||||||
|
@ -113,6 +114,7 @@ ripper_init_eventids2(void)
|
||||||
set_id2(label_end);
|
set_id2(label_end);
|
||||||
set_id2(tlambda);
|
set_id2(tlambda);
|
||||||
set_id2(tlambeg);
|
set_id2(tlambeg);
|
||||||
|
set_id2(tnumparam);
|
||||||
|
|
||||||
set_id2(ignored_nl);
|
set_id2(ignored_nl);
|
||||||
set_id2(comment);
|
set_id2(comment);
|
||||||
|
@ -276,6 +278,7 @@ static const struct token_assoc {
|
||||||
{tLABEL_END, O(label_end)},
|
{tLABEL_END, O(label_end)},
|
||||||
{tLAMBDA, O(tlambda)},
|
{tLAMBDA, O(tlambda)},
|
||||||
{tLAMBEG, O(tlambeg)},
|
{tLAMBEG, O(tlambeg)},
|
||||||
|
{tNUMPARAM, O(tnumparam)},
|
||||||
|
|
||||||
/* ripper specific tokens */
|
/* ripper specific tokens */
|
||||||
{tIGNORED_NL, O(ignored_nl)},
|
{tIGNORED_NL, O(ignored_nl)},
|
||||||
|
|
121
parse.y
121
parse.y
|
@ -167,6 +167,8 @@ struct local_vars {
|
||||||
struct local_vars *prev;
|
struct local_vars *prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define NUMPARAM_MAX 100 /* INT_MAX */
|
||||||
|
|
||||||
#define DVARS_INHERIT ((void*)1)
|
#define DVARS_INHERIT ((void*)1)
|
||||||
#define DVARS_TOPSCOPE NULL
|
#define DVARS_TOPSCOPE NULL
|
||||||
#define DVARS_TERMINAL_P(tbl) ((tbl) == DVARS_INHERIT || (tbl) == DVARS_TOPSCOPE)
|
#define DVARS_TERMINAL_P(tbl) ((tbl) == DVARS_INHERIT || (tbl) == DVARS_TOPSCOPE)
|
||||||
|
@ -244,6 +246,8 @@ struct parser_params {
|
||||||
rb_ast_t *ast;
|
rb_ast_t *ast;
|
||||||
int node_id;
|
int node_id;
|
||||||
|
|
||||||
|
int max_numparam;
|
||||||
|
|
||||||
unsigned int command_start:1;
|
unsigned int command_start:1;
|
||||||
unsigned int eofp: 1;
|
unsigned int eofp: 1;
|
||||||
unsigned int ruby__end__seen: 1;
|
unsigned int ruby__end__seen: 1;
|
||||||
|
@ -413,6 +417,8 @@ static NODE *method_add_block(struct parser_params*p, NODE *m, NODE *b, const YY
|
||||||
static NODE *new_args(struct parser_params*,NODE*,NODE*,ID,NODE*,NODE*,const YYLTYPE*);
|
static NODE *new_args(struct parser_params*,NODE*,NODE*,ID,NODE*,NODE*,const YYLTYPE*);
|
||||||
static NODE *new_args_tail(struct parser_params*,NODE*,ID,ID,const YYLTYPE*);
|
static NODE *new_args_tail(struct parser_params*,NODE*,ID,ID,const YYLTYPE*);
|
||||||
static NODE *new_kw_arg(struct parser_params *p, NODE *k, const YYLTYPE *loc);
|
static NODE *new_kw_arg(struct parser_params *p, NODE *k, const YYLTYPE *loc);
|
||||||
|
static NODE *args_with_numbered(struct parser_params*,NODE*,int);
|
||||||
|
static ID numparam_id(struct parser_params*,int);
|
||||||
|
|
||||||
static VALUE negate_lit(struct parser_params*, VALUE);
|
static VALUE negate_lit(struct parser_params*, VALUE);
|
||||||
static NODE *ret_args(struct parser_params*,NODE*);
|
static NODE *ret_args(struct parser_params*,NODE*);
|
||||||
|
@ -686,6 +692,12 @@ new_args_tail(struct parser_params *p, VALUE kw_args, VALUE kw_rest_arg, VALUE b
|
||||||
return (VALUE)t;
|
return (VALUE)t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline VALUE
|
||||||
|
args_with_numbered(struct parser_params *p, VALUE args, int max_numparam)
|
||||||
|
{
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
#define new_defined(p,expr,loc) dispatch1(defined, (expr))
|
#define new_defined(p,expr,loc) dispatch1(defined, (expr))
|
||||||
|
|
||||||
static VALUE heredoc_dedent(struct parser_params*,VALUE);
|
static VALUE heredoc_dedent(struct parser_params*,VALUE);
|
||||||
|
@ -854,6 +866,7 @@ static void token_info_warn(struct parser_params *p, const char *token, token_in
|
||||||
%token <node> tBACK_REF "back reference"
|
%token <node> tBACK_REF "back reference"
|
||||||
%token <node> tSTRING_CONTENT "literal content"
|
%token <node> tSTRING_CONTENT "literal content"
|
||||||
%token <num> tREGEXP_END
|
%token <num> tREGEXP_END
|
||||||
|
%token <num> tNUMPARAM "numbered parameter"
|
||||||
|
|
||||||
%type <node> singleton strings string string1 xstring regexp
|
%type <node> singleton strings string string1 xstring regexp
|
||||||
%type <node> string_contents xstring_contents regexp_contents string_content
|
%type <node> string_contents xstring_contents regexp_contents string_content
|
||||||
|
@ -3118,6 +3131,7 @@ block_param_def : '|' opt_bv_decl '|'
|
||||||
}
|
}
|
||||||
| tOROP
|
| tOROP
|
||||||
{
|
{
|
||||||
|
p->max_numparam = -1;
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = 0;
|
$$ = 0;
|
||||||
/*% %*/
|
/*% %*/
|
||||||
|
@ -3126,6 +3140,7 @@ block_param_def : '|' opt_bv_decl '|'
|
||||||
| '|' block_param opt_bv_decl '|'
|
| '|' block_param opt_bv_decl '|'
|
||||||
{
|
{
|
||||||
p->cur_arg = 0;
|
p->cur_arg = 0;
|
||||||
|
p->max_numparam = -1;
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
/*% %*/
|
/*% %*/
|
||||||
|
@ -3357,20 +3372,34 @@ brace_block : '{' brace_body '}'
|
||||||
;
|
;
|
||||||
|
|
||||||
brace_body : {$<vars>$ = dyna_push(p);}
|
brace_body : {$<vars>$ = dyna_push(p);}
|
||||||
|
{
|
||||||
|
$<num>$ = p->max_numparam;
|
||||||
|
p->max_numparam = 0;
|
||||||
|
}
|
||||||
opt_block_param compstmt
|
opt_block_param compstmt
|
||||||
{
|
{
|
||||||
|
int max_numparam = p->max_numparam;
|
||||||
|
p->max_numparam = $<num>2;
|
||||||
|
$3 = args_with_numbered(p, $3, max_numparam);
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_ITER($2, $3, &@$);
|
$$ = NEW_ITER($3, $4, &@$);
|
||||||
/*% %*/
|
/*% %*/
|
||||||
/*% ripper: brace_block!(escape_Qundef($2), $3) %*/
|
/*% ripper: brace_block!(escape_Qundef($3), $4) %*/
|
||||||
dyna_pop(p, $<vars>1);
|
dyna_pop(p, $<vars>1);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
do_body : {$<vars>$ = dyna_push(p);}
|
do_body : {$<vars>$ = dyna_push(p);}
|
||||||
{CMDARG_PUSH(0);}
|
{
|
||||||
|
$<num>$ = p->max_numparam;
|
||||||
|
p->max_numparam = 0;
|
||||||
|
CMDARG_PUSH(0);
|
||||||
|
}
|
||||||
opt_block_param bodystmt
|
opt_block_param bodystmt
|
||||||
{
|
{
|
||||||
|
int max_numparam = p->max_numparam;
|
||||||
|
p->max_numparam = $<num>2;
|
||||||
|
$3 = args_with_numbered(p, $3, max_numparam);
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_ITER($3, $4, &@$);
|
$$ = NEW_ITER($3, $4, &@$);
|
||||||
/*% %*/
|
/*% %*/
|
||||||
|
@ -3773,6 +3802,13 @@ string_dvar : tGVAR
|
||||||
/*% %*/
|
/*% %*/
|
||||||
/*% ripper: var_ref!($1) %*/
|
/*% ripper: var_ref!($1) %*/
|
||||||
}
|
}
|
||||||
|
| tNUMPARAM
|
||||||
|
{
|
||||||
|
/*%%%*/
|
||||||
|
$$ = NEW_DVAR(numparam_id(p, $1), &@1);
|
||||||
|
/*% %*/
|
||||||
|
/*% ripper: var_ref!(number_arg!($1)) %*/
|
||||||
|
}
|
||||||
| backref
|
| backref
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -3828,6 +3864,13 @@ user_variable : tIDENTIFIER
|
||||||
| tGVAR
|
| tGVAR
|
||||||
| tCONSTANT
|
| tCONSTANT
|
||||||
| tCVAR
|
| tCVAR
|
||||||
|
| tNUMPARAM
|
||||||
|
{
|
||||||
|
/*%%%*/
|
||||||
|
$$ = numparam_id(p, $1);
|
||||||
|
/*% %*/
|
||||||
|
/*% ripper: number_arg!($1) %*/
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
keyword_variable: keyword_nil {$$ = KWD2EID(nil, $1);}
|
keyword_variable: keyword_nil {$$ = KWD2EID(nil, $1);}
|
||||||
|
@ -5967,6 +6010,9 @@ parser_peek_variable_name(struct parser_params *p)
|
||||||
if (++ptr >= p->lex.pend) return 0;
|
if (++ptr >= p->lex.pend) return 0;
|
||||||
c = *ptr;
|
c = *ptr;
|
||||||
}
|
}
|
||||||
|
else if (ISDIGIT(c)) {
|
||||||
|
return tSTRING_DVAR;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case '{':
|
case '{':
|
||||||
p->lex.pcur = ptr;
|
p->lex.pcur = ptr;
|
||||||
|
@ -7612,12 +7658,34 @@ parse_atmark(struct parser_params *p, const enum lex_state_e last_state)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (ISDIGIT(c)) {
|
else if (ISDIGIT(c)) {
|
||||||
RUBY_SET_YYLLOC(loc);
|
|
||||||
pushback(p, c);
|
|
||||||
if (result == tIVAR) {
|
if (result == tIVAR) {
|
||||||
compile_error(p, "`@%c' is not allowed as an instance variable name", c);
|
const char *ptr = p->lex.pcur - 1;
|
||||||
|
size_t len = p->lex.pend - ptr;
|
||||||
|
int overflow;
|
||||||
|
unsigned long n = ruby_scan_digits(ptr, len, 10, &len, &overflow);
|
||||||
|
p->lex.pcur = ptr + len;
|
||||||
|
RUBY_SET_YYLLOC(loc);
|
||||||
|
if (ptr[0] == '0') {
|
||||||
|
compile_error(p, "leading zero is not allowed as a numbered parameter");
|
||||||
|
}
|
||||||
|
else if (overflow || n > NUMPARAM_MAX) {
|
||||||
|
compile_error(p, "too large numbered parameter");
|
||||||
|
}
|
||||||
|
else if (DVARS_TERMINAL_P(p->lvtbl->args) || DVARS_TERMINAL_P(p->lvtbl->args->prev)) {
|
||||||
|
compile_error(p, "numbered parameter outside block");
|
||||||
|
}
|
||||||
|
else if (p->max_numparam < 0) {
|
||||||
|
compile_error(p, "ordinary parameter is defined");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
set_yylval_num((int)n);
|
||||||
|
SET_LEX_STATE(EXPR_ARG);
|
||||||
|
return tNUMPARAM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
RUBY_SET_YYLLOC(loc);
|
||||||
|
pushback(p, c);
|
||||||
compile_error(p, "`@@%c' is not allowed as a class variable name", c);
|
compile_error(p, "`@@%c' is not allowed as a class variable name", c);
|
||||||
}
|
}
|
||||||
parser_show_error_line(p, &loc);
|
parser_show_error_line(p, &loc);
|
||||||
|
@ -8876,6 +8944,12 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
|
||||||
return NEW_LIT(add_mark_object(p, rb_enc_from_encoding(p->enc)), loc);
|
return NEW_LIT(add_mark_object(p, rb_enc_from_encoding(p->enc)), loc);
|
||||||
}
|
}
|
||||||
switch (id_type(id)) {
|
switch (id_type(id)) {
|
||||||
|
case ID_INTERNAL:
|
||||||
|
{
|
||||||
|
int idx = vtable_included(p->lvtbl->args, id);
|
||||||
|
if (idx) return NEW_DVAR(id, loc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ID_LOCAL:
|
case ID_LOCAL:
|
||||||
if (dyna_in_block(p) && dvar_defined_ref(p, id, &vidp)) {
|
if (dyna_in_block(p) && dvar_defined_ref(p, id, &vidp)) {
|
||||||
if (id == p->cur_arg) {
|
if (id == p->cur_arg) {
|
||||||
|
@ -9331,6 +9405,15 @@ assignable0(struct parser_params *p, ID id, const char **err)
|
||||||
*err = "dynamic constant assignment";
|
*err = "dynamic constant assignment";
|
||||||
return -1;
|
return -1;
|
||||||
case ID_CLASS: return NODE_CVASGN;
|
case ID_CLASS: return NODE_CVASGN;
|
||||||
|
case ID_INTERNAL:
|
||||||
|
{
|
||||||
|
int idx = vtable_included(p->lvtbl->args, id);
|
||||||
|
if (idx) {
|
||||||
|
compile_error(p, "Can't assign to numbered parameter @%d", idx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* fallthru */
|
||||||
default:
|
default:
|
||||||
compile_error(p, "identifier %"PRIsVALUE" is not valid to set", rb_id2str(id));
|
compile_error(p, "identifier %"PRIsVALUE" is not valid to set", rb_id2str(id));
|
||||||
}
|
}
|
||||||
|
@ -9355,6 +9438,21 @@ assignable(struct parser_params *p, ID id, NODE *val, const YYLTYPE *loc)
|
||||||
if (err) yyerror1(loc, err);
|
if (err) yyerror1(loc, err);
|
||||||
return NEW_BEGIN(0, loc);
|
return NEW_BEGIN(0, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ID
|
||||||
|
numparam_id(struct parser_params *p, int idx)
|
||||||
|
{
|
||||||
|
struct vtable *args;
|
||||||
|
if (idx <= 0) return (ID)0;
|
||||||
|
if (p->max_numparam < idx) {
|
||||||
|
p->max_numparam = idx;
|
||||||
|
}
|
||||||
|
args = p->lvtbl->args;
|
||||||
|
while (idx > args->pos) {
|
||||||
|
vtable_add(args, internal_id(p));
|
||||||
|
}
|
||||||
|
return args->tbl[idx-1];
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
static VALUE
|
static VALUE
|
||||||
assignable(struct parser_params *p, VALUE lhs)
|
assignable(struct parser_params *p, VALUE lhs)
|
||||||
|
@ -10227,6 +10325,17 @@ new_args_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, ID block,
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NODE *
|
||||||
|
args_with_numbered(struct parser_params *p, NODE *args, int max_numparam)
|
||||||
|
{
|
||||||
|
if (max_numparam > 0) {
|
||||||
|
if (!args) args = new_args_tail(p, 0, 0, 0, 0);
|
||||||
|
args->nd_ainfo->pre_args_num = max_numparam;
|
||||||
|
args->nd_ainfo->rest_arg = excessed_comma;
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
static NODE*
|
static NODE*
|
||||||
dsym_node(struct parser_params *p, NODE *node, const YYLTYPE *loc)
|
dsym_node(struct parser_params *p, NODE *node, const YYLTYPE *loc)
|
||||||
{
|
{
|
||||||
|
|
|
@ -812,6 +812,12 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
|
||||||
assert_equal true, thru_next
|
assert_equal true, thru_next
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_number_arg
|
||||||
|
thru_number_arg = false
|
||||||
|
parse('proc {@1}', :on_number_arg) {thru_number_arg = true}
|
||||||
|
assert_equal true, thru_number_arg
|
||||||
|
end
|
||||||
|
|
||||||
def test_opassign
|
def test_opassign
|
||||||
thru_opassign = false
|
thru_opassign = false
|
||||||
tree = parse('a += b', :on_opassign) {thru_opassign = true}
|
tree = parse('a += b', :on_opassign) {thru_opassign = true}
|
||||||
|
@ -1477,8 +1483,11 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
|
||||||
assert_equal("unterminated regexp meets end of file", compile_error('/'))
|
assert_equal("unterminated regexp meets end of file", compile_error('/'))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_invalid_numbered_parameter_name
|
||||||
|
assert_equal("leading zero is not allowed as a numbered parameter", compile_error('proc{@0}'))
|
||||||
|
end
|
||||||
|
|
||||||
def test_invalid_instance_variable_name
|
def test_invalid_instance_variable_name
|
||||||
assert_equal("`@1' is not allowed as an instance variable name", compile_error('@1'))
|
|
||||||
assert_equal("`@' without identifiers is not allowed as an instance variable name", compile_error('@%'))
|
assert_equal("`@' without identifiers is not allowed as an instance variable name", compile_error('@%'))
|
||||||
assert_equal("`@' without identifiers is not allowed as an instance variable name", compile_error('@'))
|
assert_equal("`@' without identifiers is not allowed as an instance variable name", compile_error('@'))
|
||||||
end
|
end
|
||||||
|
|
|
@ -259,6 +259,8 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase
|
||||||
scan('embvar', '"#@ivar"')
|
scan('embvar', '"#@ivar"')
|
||||||
assert_equal ['#'],
|
assert_equal ['#'],
|
||||||
scan('embvar', '"#@@cvar"')
|
scan('embvar', '"#@@cvar"')
|
||||||
|
assert_equal ['#'],
|
||||||
|
scan('embvar', '"#@1"')
|
||||||
assert_equal [],
|
assert_equal [],
|
||||||
scan('embvar', '"#lvar"')
|
scan('embvar', '"#lvar"')
|
||||||
assert_equal [],
|
assert_equal [],
|
||||||
|
@ -348,6 +350,13 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase
|
||||||
scan('ivar', 'm(lvar, @ivar, @@cvar, $gvar)')
|
scan('ivar', 'm(lvar, @ivar, @@cvar, $gvar)')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_tnumparam
|
||||||
|
assert_equal [],
|
||||||
|
scan('tnumparam', '')
|
||||||
|
assert_equal ['@1'],
|
||||||
|
scan('tnumparam', 'proc {@1}')
|
||||||
|
end
|
||||||
|
|
||||||
def test_kw
|
def test_kw
|
||||||
assert_equal [],
|
assert_equal [],
|
||||||
scan('kw', '')
|
scan('kw', '')
|
||||||
|
@ -742,6 +751,7 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase
|
||||||
assert_equal [" E\n\n"],
|
assert_equal [" E\n\n"],
|
||||||
scan('tstring_content', "<<""'E'\n E\n\n"),
|
scan('tstring_content', "<<""'E'\n E\n\n"),
|
||||||
bug10392
|
bug10392
|
||||||
|
scan('tstring_content', "tap{<<""EOS}\n""there\n""heredoc\#@1xxx\nEOS")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_heredoc_end
|
def test_heredoc_end
|
||||||
|
|
|
@ -363,7 +363,7 @@ class TestParse < Test::Unit::TestCase
|
||||||
|
|
||||||
def test_dstr_disallowed_variable
|
def test_dstr_disallowed_variable
|
||||||
bug8375 = '[ruby-core:54885] [Bug #8375]'
|
bug8375 = '[ruby-core:54885] [Bug #8375]'
|
||||||
%w[@ @1 @. @@ @@1 @@. $ $%].each do |src|
|
%w[@ @. @@ @@1 @@. $ $%].each do |src|
|
||||||
src = '#'+src+' '
|
src = '#'+src+' '
|
||||||
str = assert_nothing_raised(SyntaxError, "#{bug8375} #{src.dump}") do
|
str = assert_nothing_raised(SyntaxError, "#{bug8375} #{src.dump}") do
|
||||||
break eval('"'+src+'"')
|
break eval('"'+src+'"')
|
||||||
|
@ -378,15 +378,15 @@ class TestParse < Test::Unit::TestCase
|
||||||
|
|
||||||
def assert_disallowed_variable(type, noname, invalid)
|
def assert_disallowed_variable(type, noname, invalid)
|
||||||
noname.each do |name|
|
noname.each do |name|
|
||||||
assert_syntax_error("a = #{name}", "`#{noname[0]}' without identifiers is not allowed as #{type} variable name")
|
assert_syntax_error("proc{a = #{name} }", "`#{noname[0]}' without identifiers is not allowed as #{type} variable name")
|
||||||
end
|
end
|
||||||
invalid.each do |name|
|
invalid.each do |name|
|
||||||
assert_syntax_error("a = #{name}", "`#{name}' is not allowed as #{type} variable name")
|
assert_syntax_error("proc {a = #{name} }", "`#{name}' is not allowed as #{type} variable name")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_disallowed_instance_variable
|
def test_disallowed_instance_variable
|
||||||
assert_disallowed_variable("an instance", %w[@ @.], %w[@1])
|
assert_disallowed_variable("an instance", %w[@ @.], %w[])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_disallowed_class_variable
|
def test_disallowed_class_variable
|
||||||
|
|
|
@ -1291,6 +1291,19 @@ eom
|
||||||
assert_valid_syntax('obj::foo (1) {}')
|
assert_valid_syntax('obj::foo (1) {}')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_numbered_parameter
|
||||||
|
assert_valid_syntax('proc {@1}')
|
||||||
|
assert_equal(3, eval('[1,2].then {@1+@2}'))
|
||||||
|
assert_equal("12", eval('[1,2].then {"#@1#@2"}'))
|
||||||
|
assert_syntax_error('proc {|| @1}', /ordinary parameter is defined/)
|
||||||
|
assert_syntax_error('proc {|x| @1}', /ordinary parameter is defined/)
|
||||||
|
assert_syntax_error('proc {@1 = nil}', /Can't assign to numbered parameter @1/)
|
||||||
|
assert_syntax_error('proc {@01}', /leading zero/)
|
||||||
|
assert_syntax_error('proc {@1_}', /unexpected/)
|
||||||
|
assert_syntax_error('proc {@9999999999999999}', /too large/)
|
||||||
|
assert_syntax_error('@1', /outside block/)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def not_label(x) @result = x; @not_label ||= nil end
|
def not_label(x) @result = x; @not_label ||= nil end
|
||||||
|
|
Загрузка…
Ссылка в новой задаче