Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve MatchData#dup #1792

Merged
merged 4 commits into from
Nov 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Bug fixes:
Compatibility:

* Implemented `String#start_with?(Regexp)` (#1771, @zhublik).
* Implemented `MatchData#dup` (#1792, @XrXr).

Performance:

Expand Down
7 changes: 7 additions & 0 deletions spec/ruby/core/matchdata/begin_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,11 @@
match_data.begin(:æ).should == 1
end
end

context "when uninitialized" do
it "raises TypeError" do
match_data = MatchData.allocate
-> { match_data.begin(0) }.should raise_error(TypeError)
end
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/captures_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
require_relative '../../spec_helper'

describe "MatchData#captures" do
it "raises TypeError when uninitialized" do
match_data = MatchData.allocate
-> { match_data.captures }.should raise_error(TypeError)
end

it "returns an array of the match captures" do
/(.)(.)(\d+)(\d)/.match("THX1138.").captures.should == ["H","X","113","8"]
end
Expand Down
14 changes: 14 additions & 0 deletions spec/ruby/core/matchdata/dup_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require_relative '../../spec_helper'

describe "MatchData#dup" do
it "duplicates the match data" do
original = /ll/.match("hello")
original.instance_variable_set(:@custom_ivar, 42)
duplicate = original.dup

duplicate.instance_variable_get(:@custom_ivar).should == 42
original.regexp.should == duplicate.regexp
original.string.should == duplicate.string
original.offset(0).should == duplicate.offset(0)
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/element_reference_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
require_relative '../../spec_helper'

describe "MatchData#[]" do
it "raises TypeError when uninitialized" do
match_data = MatchData.allocate
-> { match_data[1] }.should raise_error(TypeError)
end

it "acts as normal array indexing [index]" do
md = /(.)(.)(\d+)(\d)/.match("THX1138.")

Expand Down
7 changes: 7 additions & 0 deletions spec/ruby/core/matchdata/end_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,11 @@
match_data.end(:æ).should == 2
end
end

context "when uninitialized" do
it "raises TypeError" do
match_data = MatchData.allocate
-> { match_data.end(0) }.should raise_error(TypeError)
end
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/inspect_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
@match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
end

it "returns a String when receiver is uninitialized" do
match_data = MatchData.allocate
match_data.inspect.should be_kind_of(String)
end

it "returns a String" do
@match_data.inspect.should be_kind_of(String)
end
Expand Down
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/named_captures_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,9 @@
it 'returns the latest matched capture, even if a later one that does not match exists' do
/\A(?<a>.)(?<b>.)(?<b>.)(?<a>.)?\z/.match('012').named_captures.should == { 'a' => '0', 'b' => '2' }
end

it "raises TypeError when uninitialized" do
match_data = MatchData.allocate
-> { match_data.named_captures }.should raise_error(TypeError)
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/names_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,9 @@
r = /(?<hay>hay)(?<dot>.)(?<hay>tack)/
'haystack'.match(r).names.should == r.names
end

it "raises TypeError when uninitialized" do
match_data = MatchData.allocate
-> { match_data.names }.should raise_error(TypeError)
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/offset_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,9 @@
match_data.offset(4).should == [6, 7]
end
end

it "raises TypeError when uninitialized" do
match_data = MatchData.allocate
-> { match_data.offset(0) }.should raise_error(TypeError)
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/post_match_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,9 @@
str = "abc".force_encoding Encoding::ISO_8859_1
str.match(/c/).post_match.encoding.should equal(Encoding::ISO_8859_1)
end

it "raises TypeError when uninitialized" do
match_data = MatchData.allocate
-> { match_data.post_match }.should raise_error(TypeError)
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/pre_match_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,9 @@
str = "abc".force_encoding Encoding::ISO_8859_1
str.match(/a/).pre_match.encoding.should equal(Encoding::ISO_8859_1)
end

it "raises TypeError when uninitialized" do
match_data = MatchData.allocate
-> { match_data.pre_match }.should raise_error(TypeError)
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/regexp_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,9 @@
'he[[o'.gsub('[', ']')
$~.regexp.should == /\[/
end

it "raises TypeError when uninitialized" do
match_data = MatchData.allocate
-> { match_data.regexp }.should raise_error(TypeError)
end
end
11 changes: 11 additions & 0 deletions spec/ruby/core/matchdata/shared/eql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,15 @@
a = 'haystack'.match(/hay/)
a.send(@method, Object.new).should be_false
end

it "returns false if arguments are different and both are uninitialized" do
a = MatchData.allocate
b = MatchData.allocate
a.send(@method, b).should be_false
end

it "returns true if arguments are the identical and uninitialized" do
match_data = MatchData.allocate
match_data.send(@method, match_data).should be_true
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/shared/length.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,9 @@
it "length should return the number of elements in the match array" do
/(.)(.)(\d+)(\d)/.match("THX1138.").send(@method).should == 5
end

it "raises TypeError when uninitialized" do
match_data = MatchData.allocate
-> { match_data.send(@method) }.should raise_error(TypeError)
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/string_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,9 @@
$~.string.should == 'he[[o'
$~.string.frozen?.should == true
end

it "raises TypeError when uninitialized" do
match_data = MatchData.allocate
-> { match_data.string }.should raise_error(TypeError)
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/to_a_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@
it "returns an array of matches" do
/(.)(.)(\d+)(\d)/.match("THX1138.").to_a.should == ["HX1138", "H", "X", "113", "8"]
end

it "raises TypeError when uninitialized" do
match_data = MatchData.allocate
-> { match_data.to_a }.should raise_error(TypeError)
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/to_s_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@
it "returns the entire matched string" do
/(.)(.)(\d+)(\d)/.match("THX1138.").to_s.should == "HX1138"
end

it "raises TypeError when uninitialized" do
match_data = MatchData.allocate
-> { match_data.to_s }.should raise_error(TypeError)
end
end
5 changes: 5 additions & 0 deletions spec/ruby/core/matchdata/values_at_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@
it 'takes names and indices' do
/\A(?<a>.)(?<b>.)\z/.match('01').values_at(0, 1, 2, :a, :b).should == ['01', '0', '1', '0', '1']
end

it "raises TypeError when uninitialized" do
match_data = MatchData.allocate
-> { match_data.values_at(0) }.should raise_error(TypeError)
end
end
20 changes: 20 additions & 0 deletions src/main/java/org/truffleruby/core/regexp/MatchDataGuards.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 2.0, or
* GNU General Public License version 2, or
* GNU Lesser General Public License version 2.1.
*/

package org.truffleruby.core.regexp;

import com.oracle.truffle.api.object.DynamicObject;
import org.truffleruby.Layouts;

public class MatchDataGuards {
public static boolean isInitialized(DynamicObject matchData) {
return Layouts.MATCH_DATA.getSource(matchData) != null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,26 @@ public interface MatchDataLayout extends BasicObjectLayout {
DynamicObjectFactory createMatchDataShape(DynamicObject logicalClass,
DynamicObject metaClass);

Object[] build(DynamicObject source, DynamicObject regexp, Region region, @Nullable Region charOffsets);
Object[] build(@Nullable DynamicObject source, @Nullable DynamicObject regexp, @Nullable Region region,
@Nullable Region charOffsets);

boolean isMatchData(DynamicObject object);

boolean isMatchData(Object object);

DynamicObject getSource(DynamicObject object);

void setSource(DynamicObject object, DynamicObject value);

/** Either a Regexp or a String for the case of String#gsub(String) */
DynamicObject getRegexp(DynamicObject object);

void setRegexp(DynamicObject object, DynamicObject value);

Region getRegion(DynamicObject object);

void setRegion(DynamicObject object, Region value);

Region getCharOffsets(DynamicObject object);

void setCharOffsets(DynamicObject object, Region value);
Expand Down
Loading