mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
change DOTQ
* defs/id.def (token_ops), parse.y (parser_yylex): change DOTQ from ".?" to "&.". [ruby-core:71363] [Feature #11537] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52462 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
dfa75017be
commit
837babd564
9 changed files with 45 additions and 40 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
Fri Nov 6 12:39:21 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
|
* defs/id.def (token_ops), parse.y (parser_yylex): change DOTQ
|
||||||
|
from ".?" to "&.". [ruby-core:71363] [Feature #11537]
|
||||||
|
|
||||||
Fri Nov 6 09:01:26 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Fri Nov 6 09:01:26 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* parse.y (kwd_append): fix segv after invalid keyword argument,
|
* parse.y (kwd_append): fix segv after invalid keyword argument,
|
||||||
|
|
8
NEWS
8
NEWS
|
@ -20,17 +20,17 @@ with all sufficient information, see the ChangeLog file.
|
||||||
|
|
||||||
* safe navigation operator:
|
* safe navigation operator:
|
||||||
|
|
||||||
* new method call syntax, `object.?foo', method #foo is called on
|
* new method call syntax, `object&.foo', method #foo is called on
|
||||||
`object' if it is not nil.
|
`object' if it is not nil.
|
||||||
this is similar to `try!' in Active Support, except:
|
this is similar to `try!' in Active Support, except:
|
||||||
* method name is syntactically required
|
* method name is syntactically required
|
||||||
obj.try! {} # valid
|
obj.try! {} # valid
|
||||||
obj.? {} # syntax error
|
obj&. {} # syntax error
|
||||||
* arguments are evaluated only if a call is made:
|
* arguments are evaluated only if a call is made:
|
||||||
obj.try!(:foo, bar()) # bar() is always evaluated
|
obj.try!(:foo, bar()) # bar() is always evaluated
|
||||||
obj.?foo(bar()) # bar() is conditionally evaluated
|
obj&.foo(bar()) # bar() is conditionally evaluated
|
||||||
* attribute assignment is valid
|
* attribute assignment is valid
|
||||||
obj.?attr += 1
|
obj&.attr += 1
|
||||||
|
|
||||||
=== Core classes updates (outstanding ones only)
|
=== Core classes updates (outstanding ones only)
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ token_ops = %[\
|
||||||
COLON3 ::
|
COLON3 ::
|
||||||
ANDOP &&
|
ANDOP &&
|
||||||
OROP ||
|
OROP ||
|
||||||
DOTQ .?
|
DOTQ &.
|
||||||
]
|
]
|
||||||
|
|
||||||
class KeywordError < RuntimeError
|
class KeywordError < RuntimeError
|
||||||
|
|
|
@ -615,15 +615,15 @@ module Net
|
||||||
result = String.new
|
result = String.new
|
||||||
end
|
end
|
||||||
begin
|
begin
|
||||||
f.?binmode
|
f&.binmode
|
||||||
retrbinary("RETR #{remotefile}", blocksize, rest_offset) do |data|
|
retrbinary("RETR #{remotefile}", blocksize, rest_offset) do |data|
|
||||||
f.?write(data)
|
f&.write(data)
|
||||||
block.?(data)
|
block&.(data)
|
||||||
result.?concat(data)
|
result&.concat(data)
|
||||||
end
|
end
|
||||||
return result
|
return result
|
||||||
ensure
|
ensure
|
||||||
f.?close
|
f&.close
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -646,13 +646,13 @@ module Net
|
||||||
begin
|
begin
|
||||||
retrlines("RETR #{remotefile}") do |line, newline|
|
retrlines("RETR #{remotefile}") do |line, newline|
|
||||||
l = newline ? line + "\n" : line
|
l = newline ? line + "\n" : line
|
||||||
f.?print(l)
|
f&.print(l)
|
||||||
block.?(line, newline)
|
block&.(line, newline)
|
||||||
result.?concat(l)
|
result&.concat(l)
|
||||||
end
|
end
|
||||||
return result
|
return result
|
||||||
ensure
|
ensure
|
||||||
f.?close
|
f&.close
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
10
parse.y
10
parse.y
|
@ -875,7 +875,7 @@ static void token_info_pop(struct parser_params*, const char *token, size_t len)
|
||||||
%token tASET RUBY_TOKEN(ASET) "[]="
|
%token tASET RUBY_TOKEN(ASET) "[]="
|
||||||
%token tLSHFT RUBY_TOKEN(LSHFT) "<<"
|
%token tLSHFT RUBY_TOKEN(LSHFT) "<<"
|
||||||
%token tRSHFT RUBY_TOKEN(RSHFT) ">>"
|
%token tRSHFT RUBY_TOKEN(RSHFT) ">>"
|
||||||
%token tDOTQ RUBY_TOKEN(DOTQ) ".?"
|
%token tDOTQ RUBY_TOKEN(DOTQ) "&."
|
||||||
%token tCOLON2 "::"
|
%token tCOLON2 "::"
|
||||||
%token tCOLON3 ":: at EXPR_BEG"
|
%token tCOLON3 ":: at EXPR_BEG"
|
||||||
%token <id> tOP_ASGN /* +=, -= etc. */
|
%token <id> tOP_ASGN /* +=, -= etc. */
|
||||||
|
@ -8276,6 +8276,10 @@ parser_yylex(struct parser_params *parser)
|
||||||
lex_state = EXPR_BEG;
|
lex_state = EXPR_BEG;
|
||||||
return tOP_ASGN;
|
return tOP_ASGN;
|
||||||
}
|
}
|
||||||
|
else if (c == '.') {
|
||||||
|
lex_state = EXPR_DOT;
|
||||||
|
return tDOTQ;
|
||||||
|
}
|
||||||
pushback(c);
|
pushback(c);
|
||||||
if (IS_SPCARG(c)) {
|
if (IS_SPCARG(c)) {
|
||||||
rb_warning0("`&' interpreted as argument prefix");
|
rb_warning0("`&' interpreted as argument prefix");
|
||||||
|
@ -8380,10 +8384,6 @@ parser_yylex(struct parser_params *parser)
|
||||||
pushback(c);
|
pushback(c);
|
||||||
return tDOT2;
|
return tDOT2;
|
||||||
}
|
}
|
||||||
if (c == '?') {
|
|
||||||
lex_state = EXPR_DOT;
|
|
||||||
return tDOTQ;
|
|
||||||
}
|
|
||||||
pushback(c);
|
pushback(c);
|
||||||
if (c != -1 && ISDIGIT(c)) {
|
if (c != -1 && ISDIGIT(c)) {
|
||||||
yyerror("no .<digit> floating literal anymore; put 0 before dot");
|
yyerror("no .<digit> floating literal anymore; put 0 before dot");
|
||||||
|
|
|
@ -391,14 +391,14 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
|
||||||
assert_equal "[call(vcall(foo),::,call,[])]", tree
|
assert_equal "[call(vcall(foo),::,call,[])]", tree
|
||||||
|
|
||||||
thru_call = false
|
thru_call = false
|
||||||
tree = parse("self.?foo", :on_call) {thru_call = true}
|
tree = parse("self&.foo", :on_call) {thru_call = true}
|
||||||
assert_equal true, thru_call
|
assert_equal true, thru_call
|
||||||
assert_equal "[call(ref(self),.?,foo)]", tree
|
assert_equal "[call(ref(self),&.,foo)]", tree
|
||||||
|
|
||||||
thru_call = false
|
thru_call = false
|
||||||
tree = parse("self.?foo()", :on_call) {thru_call = true}
|
tree = parse("self&.foo()", :on_call) {thru_call = true}
|
||||||
assert_equal true, thru_call
|
assert_equal true, thru_call
|
||||||
assert_equal "[call(ref(self),.?,foo,[])]", tree
|
assert_equal "[call(ref(self),&.,foo,[])]", tree
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_excessed_comma
|
def test_excessed_comma
|
||||||
|
@ -569,7 +569,7 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
|
||||||
assert_equal("[defs(vcall(foo),.,bar,[],bodystmt([void()]))]", tree)
|
assert_equal("[defs(vcall(foo),.,bar,[],bodystmt([void()]))]", tree)
|
||||||
|
|
||||||
thru_parse_error = false
|
thru_parse_error = false
|
||||||
tree = parse('def foo.?bar; end', :on_parse_error) {thru_parse_error = true}
|
tree = parse('def foo&.bar; end', :on_parse_error) {thru_parse_error = true}
|
||||||
assert_equal(true, thru_parse_error)
|
assert_equal(true, thru_parse_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -796,9 +796,9 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
|
||||||
assert_equal "[opassign(field(ref(self),.,foo),+=,1)]", tree
|
assert_equal "[opassign(field(ref(self),.,foo),+=,1)]", tree
|
||||||
|
|
||||||
thru_opassign = false
|
thru_opassign = false
|
||||||
tree = parse("self.?foo += 1", :on_opassign) {thru_opassign = true}
|
tree = parse("self&.foo += 1", :on_opassign) {thru_opassign = true}
|
||||||
assert_equal true, thru_opassign
|
assert_equal true, thru_opassign
|
||||||
assert_equal "[opassign(field(ref(self),.?,foo),+=,1)]", tree
|
assert_equal "[opassign(field(ref(self),&.,foo),+=,1)]", tree
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_opassign_error
|
def test_opassign_error
|
||||||
|
|
|
@ -535,8 +535,8 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase
|
||||||
scan('op', ':[]')
|
scan('op', ':[]')
|
||||||
assert_equal ['[]='],
|
assert_equal ['[]='],
|
||||||
scan('op', ':[]=')
|
scan('op', ':[]=')
|
||||||
assert_equal ['.?'],
|
assert_equal ['&.'],
|
||||||
scan('op', 'a.?f')
|
scan('op', 'a&.f')
|
||||||
assert_equal [],
|
assert_equal [],
|
||||||
scan('op', %q[`make all`])
|
scan('op', %q[`make all`])
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,22 +35,22 @@ class TestCall < Test::Unit::TestCase
|
||||||
def test_safe_call
|
def test_safe_call
|
||||||
s = Struct.new(:x, :y, :z)
|
s = Struct.new(:x, :y, :z)
|
||||||
o = s.new("x")
|
o = s.new("x")
|
||||||
assert_equal("X", o.x.?upcase)
|
assert_equal("X", o.x&.upcase)
|
||||||
assert_nil(o.y.?upcase)
|
assert_nil(o.y&.upcase)
|
||||||
assert_equal("x", o.x)
|
assert_equal("x", o.x)
|
||||||
o.?x = 6
|
o&.x = 6
|
||||||
assert_equal(6, o.x)
|
assert_equal(6, o.x)
|
||||||
o.?x *= 7
|
o&.x *= 7
|
||||||
assert_equal(42, o.x)
|
assert_equal(42, o.x)
|
||||||
o.?y = 5
|
o&.y = 5
|
||||||
assert_equal(5, o.y)
|
assert_equal(5, o.y)
|
||||||
o.?z ||= 6
|
o&.z ||= 6
|
||||||
assert_equal(6, o.z)
|
assert_equal(6, o.z)
|
||||||
|
|
||||||
o = nil
|
o = nil
|
||||||
assert_nil(o.?x)
|
assert_nil(o&.x)
|
||||||
assert_nothing_raised(NoMethodError) {o.?x = 6}
|
assert_nothing_raised(NoMethodError) {o&.x = 6}
|
||||||
assert_nothing_raised(NoMethodError) {o.?x *= 7}
|
assert_nothing_raised(NoMethodError) {o&.x *= 7}
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_safe_call_evaluate_arguments_only_method_call_is_made
|
def test_safe_call_evaluate_arguments_only_method_call_is_made
|
||||||
|
@ -59,10 +59,10 @@ class TestCall < Test::Unit::TestCase
|
||||||
s = Struct.new(:x, :y)
|
s = Struct.new(:x, :y)
|
||||||
o = s.new(["a", "b", "c"])
|
o = s.new(["a", "b", "c"])
|
||||||
|
|
||||||
o.y.?at(proc.call)
|
o.y&.at(proc.call)
|
||||||
assert_equal(0, count)
|
assert_equal(0, count)
|
||||||
|
|
||||||
o.x.?at(proc.call)
|
o.x&.at(proc.call)
|
||||||
assert_equal(1, count)
|
assert_equal(1, count)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -181,7 +181,7 @@ class TestISeq < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_safe_call_chain
|
def test_safe_call_chain
|
||||||
src = "a.?a.?a.?a.?a.?a"
|
src = "a&.a&.a&.a&.a&.a"
|
||||||
body = compile(src, __LINE__, {peephole_optimization: true}).to_a[13]
|
body = compile(src, __LINE__, {peephole_optimization: true}).to_a[13]
|
||||||
labels = body.select {|op, arg| op == :branchnil}.map {|op, arg| arg}
|
labels = body.select {|op, arg| op == :branchnil}.map {|op, arg| arg}
|
||||||
assert_equal(1, labels.uniq.size)
|
assert_equal(1, labels.uniq.size)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue