Misc #15723 ยป implicit-param.diff
bootstraptest/test_syntax.rb | ||
---|---|---|
assert_syntax_error "unterminated string meets end of file", '().."', '[ruby-dev:29732]'
|
||
assert_equal %q{[]}, %q{$&;[]}, '[ruby-dev:31068]'
|
||
assert_syntax_error "syntax error, unexpected *, expecting '}'", %q{{*0}}, '[ruby-dev:31072]'
|
||
assert_syntax_error "leading zero is not allowed as a numbered parameter", %q{@0..0}, '[ruby-dev:31095]'
|
||
assert_syntax_error "`@0' is not allowed as an instance variable name", %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 set", %q{0..$00=1}
|
||
assert_equal %q{0}, %q{[*0];0}, '[ruby-dev:31102]'
|
ext/ripper/eventids2.c | ||
---|---|---|
ID ripper_id_label_end;
|
||
ID ripper_id_tlambda;
|
||
ID ripper_id_tlambeg;
|
||
ID ripper_id_tnumparam;
|
||
ID ripper_id_timplicitparam;
|
||
ID ripper_id_ignored_nl;
|
||
ID ripper_id_comment;
|
||
... | ... | |
set_id2(label_end);
|
||
set_id2(tlambda);
|
||
set_id2(tlambeg);
|
||
set_id2(tnumparam);
|
||
set_id2(timplicitparam);
|
||
set_id2(ignored_nl);
|
||
set_id2(comment);
|
||
... | ... | |
{tLABEL_END, O(label_end)},
|
||
{tLAMBDA, O(tlambda)},
|
||
{tLAMBEG, O(tlambeg)},
|
||
{tNUMPARAM, O(tnumparam)},
|
||
{tIMPLICITPARAM, O(timplicitparam)},
|
||
/* ripper specific tokens */
|
||
{tIGNORED_NL, O(ignored_nl)},
|
parse.y | ||
---|---|---|
struct local_vars *prev;
|
||
};
|
||
#define NUMPARAM_MAX 100 /* INT_MAX */
|
||
#define DVARS_INHERIT ((void*)1)
|
||
#define DVARS_TOPSCOPE NULL
|
||
#define DVARS_TERMINAL_P(tbl) ((tbl) == DVARS_INHERIT || (tbl) == DVARS_TOPSCOPE)
|
||
... | ... | |
rb_ast_t *ast;
|
||
int node_id;
|
||
int max_numparam;
|
||
unsigned int command_start:1;
|
||
unsigned int eofp: 1;
|
||
unsigned int ruby__end__seen: 1;
|
||
... | ... | |
# endif
|
||
unsigned int error_p: 1;
|
||
unsigned int cr_seen: 1;
|
||
unsigned int has_explicit_params: 1;
|
||
unsigned int has_implicit_param: 1;
|
||
#ifndef RIPPER
|
||
/* Ruby core only */
|
||
... | ... | |
static NODE *new_hash_pattern_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, 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 NODE *args_with_implicit(struct parser_params*,NODE*);
|
||
static VALUE negate_lit(struct parser_params*, VALUE);
|
||
static NODE *ret_args(struct parser_params*,NODE*);
|
||
... | ... | |
YYLTYPE *rb_parser_set_location_from_strterm_heredoc(struct parser_params *p, rb_strterm_heredoc_t *here, YYLTYPE *yylloc);
|
||
YYLTYPE *rb_parser_set_location_of_none(struct parser_params *p, YYLTYPE *yylloc);
|
||
YYLTYPE *rb_parser_set_location(struct parser_params *p, YYLTYPE *yylloc);
|
||
ID rb_parser_numparam_id(struct parser_params *p, int num);
|
||
ID rb_parser_implicit_param_id(struct parser_params *p);
|
||
RUBY_SYMBOL_EXPORT_END
|
||
#define numparam_id rb_parser_numparam_id
|
||
#define implicit_param_id rb_parser_implicit_param_id
|
||
static void parser_token_value_print(struct parser_params *p, enum yytokentype type, const YYSTYPE *valp);
|
||
static ID formal_argument(struct parser_params*, ID);
|
||
... | ... | |
}
|
||
static inline VALUE
|
||
args_with_numbered(struct parser_params *p, VALUE args, int max_numparam)
|
||
args_with_implicit(struct parser_params *p, VALUE args)
|
||
{
|
||
return args;
|
||
}
|
||
... | ... | |
%token <id> tCONSTANT "constant"
|
||
%token <id> tCVAR "class variable"
|
||
%token <id> tLABEL
|
||
%token <id> tNUMPARAM "numbered parameter"
|
||
%token <id> tIMPLICITPARAM "implicit parameter"
|
||
%token <node> tINTEGER "integer literal"
|
||
%token <node> tFLOAT "float literal"
|
||
%token <node> tRATIONAL "rational literal"
|
||
... | ... | |
}
|
||
| tOROP
|
||
{
|
||
p->max_numparam = -1;
|
||
p->has_explicit_params = 1;
|
||
/*%%%*/
|
||
$$ = 0;
|
||
/*% %*/
|
||
... | ... | |
| '|' block_param opt_bv_decl '|'
|
||
{
|
||
p->cur_arg = 0;
|
||
p->max_numparam = -1;
|
||
p->has_explicit_params = 1;
|
||
/*%%%*/
|
||
$$ = $2;
|
||
/*% %*/
|
||
... | ... | |
$<num>$ = p->lex.lpar_beg;
|
||
p->lex.lpar_beg = p->lex.paren_nest;
|
||
}
|
||
{
|
||
$<num>$ = p->max_numparam;
|
||
}
|
||
f_larglist
|
||
{
|
||
CMDARG_PUSH(0);
|
||
}
|
||
lambda_body
|
||
{
|
||
int max_numparam = p->max_numparam;
|
||
p->lex.lpar_beg = $<num>2;
|
||
p->max_numparam = $<num>3;
|
||
CMDARG_POP();
|
||
$4 = args_with_numbered(p, $4, max_numparam);
|
||
$3 = args_with_implicit(p, $3);
|
||
/*%%%*/
|
||
{
|
||
YYLTYPE loc = code_loc_gen(&@4, &@6);
|
||
$$ = NEW_LAMBDA($4, $6, &loc);
|
||
nd_set_line($$->nd_body, @6.end_pos.lineno);
|
||
nd_set_line($$, @4.end_pos.lineno);
|
||
YYLTYPE loc = code_loc_gen(&@3, &@5);
|
||
$$ = NEW_LAMBDA($3, $5, &loc);
|
||
nd_set_line($$->nd_body, @5.end_pos.lineno);
|
||
nd_set_line($$, @3.end_pos.lineno);
|
||
}
|
||
/*% %*/
|
||
/*% ripper: lambda!($4, $6) %*/
|
||
/*% ripper: lambda!($3, $5) %*/
|
||
dyna_pop(p, $<vars>1);
|
||
}
|
||
;
|
||
... | ... | |
{
|
||
/*%%%*/
|
||
$$ = $2;
|
||
p->max_numparam = -1;
|
||
p->has_explicit_params = 1;
|
||
/*% %*/
|
||
/*% ripper: paren!($2) %*/
|
||
}
|
||
... | ... | |
{
|
||
/*%%%*/
|
||
if (!args_info_empty_p($1->nd_ainfo))
|
||
p->max_numparam = -1;
|
||
p->has_explicit_params = 1;
|
||
/*% %*/
|
||
$$ = $1;
|
||
}
|
||
... | ... | |
brace_body : {$<vars>$ = dyna_push(p);}
|
||
{
|
||
$<num>$ = p->max_numparam;
|
||
p->max_numparam = 0;
|
||
p->has_explicit_params = 0;
|
||
}
|
||
opt_block_param compstmt
|
||
{
|
||
int max_numparam = p->max_numparam;
|
||
p->max_numparam = $<num>2;
|
||
$3 = args_with_numbered(p, $3, max_numparam);
|
||
$3 = args_with_implicit(p, $3);
|
||
/*%%%*/
|
||
$$ = NEW_ITER($3, $4, &@$);
|
||
/*% %*/
|
||
... | ... | |
do_body : {$<vars>$ = dyna_push(p);}
|
||
{
|
||
$<num>$ = p->max_numparam;
|
||
p->max_numparam = 0;
|
||
p->has_explicit_params = 0;
|
||
CMDARG_PUSH(0);
|
||
}
|
||
opt_block_param bodystmt
|
||
{
|
||
int max_numparam = p->max_numparam;
|
||
p->max_numparam = $<num>2;
|
||
$3 = args_with_numbered(p, $3, max_numparam);
|
||
$3 = args_with_implicit(p, $3);
|
||
/*%%%*/
|
||
$$ = NEW_ITER($3, $4, &@$);
|
||
/*% %*/
|
||
... | ... | |
/*% %*/
|
||
/*% ripper: var_ref!($1) %*/
|
||
}
|
||
| tNUMPARAM
|
||
{
|
||
/*%%%*/
|
||
$$ = NEW_DVAR($1, &@1);
|
||
/*% %*/
|
||
/*% ripper: var_ref!($1) %*/
|
||
}
|
||
| backref
|
||
;
|
||
... | ... | |
| tGVAR
|
||
| tCONSTANT
|
||
| tCVAR
|
||
| tNUMPARAM
|
||
| tIMPLICITPARAM
|
||
;
|
||
keyword_variable: keyword_nil {$$ = KWD2EID(nil, $1);}
|
||
... | ... | |
| tIDENTIFIER
|
||
{
|
||
formal_argument(p, get_id($1));
|
||
p->max_numparam = -1;
|
||
p->has_explicit_params = 1;
|
||
$$ = $1;
|
||
}
|
||
;
|
||
... | ... | |
ID id = get_id($1);
|
||
arg_var(p, formal_argument(p, id));
|
||
p->cur_arg = id;
|
||
p->max_numparam = -1;
|
||
p->has_explicit_params = 1;
|
||
$$ = $1;
|
||
}
|
||
;
|
||
... | ... | |
if (++ptr >= p->lex.pend) return 0;
|
||
c = *ptr;
|
||
}
|
||
else if (ISDIGIT(c)) {
|
||
return tSTRING_DVAR;
|
||
}
|
||
break;
|
||
case '{':
|
||
p->lex.pcur = ptr;
|
||
... | ... | |
}
|
||
static bool
|
||
parser_numbered_param(struct parser_params *p, unsigned long n)
|
||
parser_implicit_param(struct parser_params *p)
|
||
{
|
||
if (DVARS_TERMINAL_P(p->lvtbl->args) || DVARS_TERMINAL_P(p->lvtbl->args->prev)) {
|
||
compile_error(p, "numbered parameter outside block");
|
||
compile_error(p, "implicit parameter outside block");
|
||
return false;
|
||
}
|
||
if (p->max_numparam < 0) {
|
||
if (p->has_explicit_params) {
|
||
compile_error(p, "ordinary parameter is defined");
|
||
return false;
|
||
}
|
||
set_yylval_name(numparam_id(p, (int)n));
|
||
p->has_implicit_param = 1;
|
||
set_yylval_name(implicit_param_id(p));
|
||
SET_LEX_STATE(EXPR_ARG);
|
||
return true;
|
||
}
|
||
... | ... | |
tokadd(p, '@');
|
||
c = nextc(p);
|
||
}
|
||
if (c == -1 || !parser_is_identchar(p)) {
|
||
if ((c == -1 || !parser_is_identchar(p)) && !ISDIGIT(c)) {
|
||
pushback(p, c);
|
||
RUBY_SET_YYLLOC(loc);
|
||
if (result == tIVAR) {
|
||
compile_error(p, "`@' without identifiers is not allowed as an instance variable name");
|
||
if (parser_implicit_param(p)) {
|
||
return tIMPLICITPARAM;
|
||
}
|
||
}
|
||
else {
|
||
compile_error(p, "`@@' without identifiers is not allowed as a class variable name");
|
||
... | ... | |
return result;
|
||
}
|
||
else if (ISDIGIT(c)) {
|
||
RUBY_SET_YYLLOC(loc);
|
||
pushback(p, c);
|
||
if (result == tIVAR) {
|
||
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 (parser_numbered_param(p, n)) {
|
||
return tNUMPARAM;
|
||
}
|
||
compile_error(p, "`@%c' is not allowed as an instance variable name", c);
|
||
}
|
||
else {
|
||
RUBY_SET_YYLLOC(loc);
|
||
pushback(p, c);
|
||
compile_error(p, "`@@%c' is not allowed as a class variable name", c);
|
||
}
|
||
parser_show_error_line(p, &loc);
|
||
... | ... | |
{
|
||
int idx = vtable_included(p->lvtbl->args, id);
|
||
if (idx) {
|
||
compile_error(p, "Can't assign to numbered parameter @%d", idx);
|
||
compile_error(p, "Can't assign to implicit parameter @");
|
||
break;
|
||
}
|
||
}
|
||
... | ... | |
}
|
||
static NODE *
|
||
args_with_numbered(struct parser_params *p, NODE *args, int max_numparam)
|
||
args_with_implicit(struct parser_params *p, NODE *args)
|
||
{
|
||
if (max_numparam > 0) {
|
||
if (p->has_implicit_param) {
|
||
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;
|
||
args->nd_ainfo->pre_args_num = 1;
|
||
}
|
||
return args;
|
||
}
|
||
ID
|
||
rb_parser_numparam_id(struct parser_params *p, int idx)
|
||
rb_parser_implicit_param_id(struct parser_params *p)
|
||
{
|
||
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) {
|
||
if (args->pos == 0) {
|
||
vtable_add(args, internal_id(p));
|
||
}
|
||
return args->tbl[idx-1];
|
||
return args->tbl[0];
|
||
}
|
||
static NODE*
|
test/ripper/test_parser_events.rb | ||
---|---|---|
assert_equal '[assign(var_field(a),ref(a))]', parse('a=a')
|
||
assert_equal '[ref(nil)]', parse('nil')
|
||
assert_equal '[ref(true)]', parse('true')
|
||
assert_include parse('proc{@1}'), '[ref(@1)]'
|
||
assert_include parse('proc{@}'), '[ref(@)]'
|
||
end
|
||
def test_vcall
|
||
... | ... | |
assert_equal("unterminated regexp meets end of file", compile_error('/'))
|
||
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
|
||
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("`@1' is not allowed as an instance variable name", compile_error('@1'))
|
||
assert_equal("implicit parameter outside block", compile_error('@%'))
|
||
assert_equal("implicit parameter outside block", compile_error('@'))
|
||
end
|
||
def test_invalid_class_variable_name
|
test/ripper/test_scanner_events.rb | ||
---|---|---|
scan('embvar', '"#@ivar"')
|
||
assert_equal ['#'],
|
||
scan('embvar', '"#@@cvar"')
|
||
assert_equal ['#'],
|
||
scan('embvar', '"#@1"')
|
||
assert_equal [],
|
||
scan('embvar', '"#lvar"')
|
||
assert_equal [],
|
||
... | ... | |
scan('ivar', 'm(lvar, @ivar, @@cvar, $gvar)')
|
||
end
|
||
def test_tnumparam
|
||
assert_equal [],
|
||
scan('tnumparam', '')
|
||
assert_equal ['@1'],
|
||
scan('tnumparam', 'proc {@1}')
|
||
def test_timplicitparam
|
||
assert_equal ['@'],
|
||
scan('timplicitparam', 'proc {@}')
|
||
end
|
||
def test_kw
|
||
... | ... | |
assert_equal [" E\n\n"],
|
||
scan('tstring_content', "<<""'E'\n E\n\n"),
|
||
bug10392
|
||
scan('tstring_content', "tap{<<""EOS}\n""there\n""heredoc\#@1xxx\nEOS")
|
||
scan('tstring_content', "tap{<<""EOS}\n""there\n""heredoc\#{@}xxx\nEOS")
|
||
end
|
||
def test_heredoc_end
|
test/ruby/test_parse.rb | ||
---|---|---|
def assert_disallowed_variable(type, noname, invalid)
|
||
noname.each do |name|
|
||
assert_syntax_error("proc{a = #{name} }", "`#{noname[0]}' without identifiers is not allowed as #{type} variable name")
|
||
assert_syntax_error("a = #{name}", "`#{noname[0]}' without identifiers is not allowed as #{type} variable name")
|
||
end
|
||
invalid.each do |name|
|
||
assert_syntax_error("proc {a = #{name} }", "`#{name}' is not allowed as #{type} variable name")
|
||
assert_syntax_error("a = #{name}", "`#{name}' is not allowed as #{type} variable name")
|
||
end
|
||
end
|
||
def test_disallowed_instance_variable
|
||
assert_disallowed_variable("an instance", %w[@ @.], %w[])
|
||
assert_syntax_error("a = @", "implicit parameter outside block")
|
||
assert_syntax_error("a = @.to_f", "implicit parameter outside block")
|
||
assert_syntax_error("a = @1", "`@1' is not allowed as an instance variable name")
|
||
end
|
||
def test_disallowed_class_variable
|
||
... | ... | |
end
|
||
def test_invalid_instance_variable
|
||
pattern = /without identifiers is not allowed as an instance variable name/
|
||
assert_raise_with_message(SyntaxError, pattern) { eval('@%') }
|
||
assert_raise_with_message(SyntaxError, pattern) { eval('@') }
|
||
assert_raise_with_message(SyntaxError, /implicit parameter outside block.*unterminated quoted string meets end of file/m) { eval('@%') }
|
||
assert_raise_with_message(SyntaxError, /implicit parameter outside block/) { eval('@') }
|
||
end
|
||
def test_invalid_class_variable
|
test/ruby/test_syntax.rb | ||
---|---|---|
assert_valid_syntax('obj::foo (1) {}')
|
||
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_equal(3, eval('->{@1+@2}.call(1,2)'))
|
||
assert_syntax_error('proc {|| @1}', /ordinary parameter is defined/)
|
||
assert_syntax_error('proc {|x| @1}', /ordinary parameter is defined/)
|
||
assert_syntax_error('->(){@1}', /ordinary parameter is defined/)
|
||
assert_syntax_error('->(x){@1}', /ordinary parameter is defined/)
|
||
assert_syntax_error('->x{@1}', /ordinary parameter is defined/)
|
||
assert_syntax_error('->x:@2{}', /ordinary parameter is defined/)
|
||
assert_syntax_error('->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/)
|
||
def test_implicit_parameter
|
||
assert_valid_syntax('proc {@}')
|
||
assert_equal(3, eval('[1,2].then {@[0]+@[1]}'))
|
||
assert_equal("12", eval('[1,2].then {"#{@[0]}#{@[1]}"}'))
|
||
assert_equal(3, eval('->{@[0]+@[1]}.call([1,2])'))
|
||
assert_syntax_error('proc {|| @}', /ordinary parameter is defined/)
|
||
assert_syntax_error('proc {|x| @}', /ordinary parameter is defined/)
|
||
assert_syntax_error('proc {|x=@|}', /ordinary parameter is defined/)
|
||
assert_syntax_error('->(){@}', /ordinary parameter is defined/)
|
||
assert_syntax_error('->(x){@}', /ordinary parameter is defined/)
|
||
assert_syntax_error('->x{@}', /ordinary parameter is defined/)
|
||
assert_syntax_error('->x:@{}', /ordinary parameter is defined/)
|
||
assert_syntax_error('->x=@{}', /ordinary parameter is defined/)
|
||
assert_syntax_error('proc {@ = nil}', /Can't assign to implicit parameter @/)
|
||
assert_syntax_error('proc {@01}', /not allowed as an instance variable name/)
|
||
assert_syntax_error('proc {@1_}', /not allowed as an instance variable name/)
|
||
assert_syntax_error('proc {@9999999999999999}', /not allowed as an instance variable name/)
|
||
assert_syntax_error('@', /outside block/)
|
||
end
|
||
private
|