1
0
Fork 0
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:
nobu 2015-11-06 03:39:23 +00:00
parent dfa75017be
commit 837babd564
9 changed files with 45 additions and 40 deletions

View file

@ -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
View file

@ -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)

View file

@ -98,7 +98,7 @@ token_ops = %[\
COLON3 :: COLON3 ::
ANDOP && ANDOP &&
OROP || OROP ||
DOTQ .? DOTQ &.
] ]
class KeywordError < RuntimeError class KeywordError < RuntimeError

View file

@ -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
View file

@ -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");

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)