Skip to content

Commit

Permalink
Merge pull request #2601 from herwinw/kernel_complex
Browse files Browse the repository at this point in the history
More coercion of string into complex
  • Loading branch information
herwinw committed Feb 13, 2025
2 parents c65cf0e + 683a3cd commit 18e1379
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 42 deletions.
4 changes: 2 additions & 2 deletions spec/core/kernel/Complex_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@

context "invalid argument" do
it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
NATFIXME 'raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding', exception: SpecFailedException do
NATFIXME 'Add encoder to to UTF-16', exception: SpecFailedException, message: /code converter not found \(UTF-8 to UTF-16\)/ do
-> {
Complex("79+4i".encode("UTF-16"))
}.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
Expand Down Expand Up @@ -117,7 +117,7 @@

context "invalid argument and exception: false passed" do
it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
NATFIXME 'raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding', exception: SpecFailedException do
NATFIXME 'Add encoder to to UTF-16', exception: SpecFailedException, message: /code converter not found \(UTF-8 to UTF-16\)/ do
-> {
Complex("79+4i".encode("UTF-16"), exception: false)
}.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
Expand Down
12 changes: 4 additions & 8 deletions spec/core/string/to_c_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@
it "allows null-byte" do
"1-2i\0".to_c.should == Complex(1, -2)
"1\0-2i".to_c.should == Complex(1, 0)
NATFIXME 'it allows null-byte', exception: SpecFailedException do
NATFIXME 'This is not a null-byte, but 0x01', exception: SpecFailedException do
"\01-2i".to_c.should == Complex(0, 0)
end
end

it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
NATFIXME 'Raise Encoding::CompatibilityError', exception: SpecFailedException, message: /should have raised Encoding::CompatibilityError/ do
NATFIXME 'Add encoder to to UTF-16', exception: SpecFailedException, message: /code converter not found \(UTF-8 to UTF-16\)/ do
-> {
'79+4i'.encode("UTF-16").to_c
}.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
Expand All @@ -45,15 +45,11 @@

ruby_version_is "3.2" do
it "treats a sequence of underscores as an end of Complex string" do
NATFIXME 'Handle single underscore', exception: SpecFailedException do
"5+3_1i".to_c.should == Complex(5, 31)
end
"5+3_1i".to_c.should == Complex(5, 31)
"5+3__1i".to_c.should == Complex(5)
"5+3___1i".to_c.should == Complex(5)

NATFIXME 'Handle single underscore', exception: SpecFailedException do
"12_3".to_c.should == Complex(123)
end
"12_3".to_c.should == Complex(123)
"12__3".to_c.should == Complex(12)
"12___3".to_c.should == Complex(12)
end
Expand Down
34 changes: 9 additions & 25 deletions spec/shared/kernel/complex.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,46 +93,32 @@
end

it "understands scientific notation for the real part" do
NATFIXME 'understands scientific notation for the real part', exception: SpecFailedException do
@object.send(@method, '2e3+4i').should == Complex(2e3,4)
end
@object.send(@method, '2e3+4i').should == Complex(2e3,4)
end

it "understands negative scientific notation for the real part" do
NATFIXME 'understands negative scientific notation for the real part', exception: SpecFailedException do
@object.send(@method, '-2e3+4i').should == Complex(-2e3,4)
end
@object.send(@method, '-2e3+4i').should == Complex(-2e3,4)
end

it "understands scientific notation for the imaginary part" do
NATFIXME 'understands scientific notation for the imaginary part', exception: SpecFailedException do
@object.send(@method, '4+2e3i').should == Complex(4, 2e3)
end
@object.send(@method, '4+2e3i').should == Complex(4, 2e3)
end

it "understands negative scientific notation for the imaginary part" do
NATFIXME 'understands negative scientific notation for the imaginary part', exception: SpecFailedException do
@object.send(@method, '4-2e3i').should == Complex(4, -2e3)
end
@object.send(@method, '4-2e3i').should == Complex(4, -2e3)
end

it "understands scientific notation for the real and imaginary part in the same String" do
NATFIXME 'understands scientific notation for the real and imaginary part in the same String', exception: SpecFailedException do
@object.send(@method, '2e3+2e4i').should == Complex(2e3,2e4)
end
@object.send(@method, '2e3+2e4i').should == Complex(2e3,2e4)
end

it "understands negative scientific notation for the real and imaginary part in the same String" do
NATFIXME 'understands negative scientific notation for the real and imaginary part in the same String', exception: SpecFailedException do
@object.send(@method, '-2e3-2e4i').should == Complex(-2e3,-2e4)
end
@object.send(@method, '-2e3-2e4i').should == Complex(-2e3,-2e4)
end

it "understands scientific notation with e and E" do
NATFIXME 'understands scientific notation with e and E', exception: SpecFailedException do
@object.send(@method, '2e3+2e4i').should == Complex(2e3, 2e4)
@object.send(@method, '2E3+2E4i').should == Complex(2e3, 2e4)
end
@object.send(@method, '2e3+2e4i').should == Complex(2e3, 2e4)
@object.send(@method, '2E3+2E4i').should == Complex(2e3, 2e4)
end

it "understands 'm@a' to mean a complex number in polar form with 'm' as the modulus, 'a' as the argument" do
Expand All @@ -152,8 +138,6 @@
end

it "understands _" do
NATFIXME 'understands _', exception: SpecFailedException do
@object.send(@method, '7_9+4_0i').should == Complex(79, 40)
end
@object.send(@method, '7_9+4_0i').should == Complex(79, 40)
end
end
19 changes: 12 additions & 7 deletions src/kernel_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ Value KernelModule::Complex(Env *env, StringObject *input, bool exception, bool
Undefined,
Integer,
Float,
Scientific,
};
auto state = State::Start;
auto real_type = Type::Undefined;
Expand All @@ -206,8 +207,7 @@ Value KernelModule::Complex(Env *env, StringObject *input, bool exception, bool
for (const char *c = input->c_str(); c < input->c_str() + input->bytesize(); c++) {
if (*c == 0) {
if (string_to_c) {
if (state != State::Start)
state = State::Finished;
state = State::Finished;
continue;
} else {
if (exception)
Expand All @@ -233,8 +233,9 @@ Value KernelModule::Complex(Env *env, StringObject *input, bool exception, bool
if (*c >= '0' && *c <= '9') {
*curr_end = c;
} else if (*c == '_') {
// TODO: Skip single underscore
if (string_to_c) {
if (c[1] && c[1] >= '0' && c[1] <= '9') {
continue; // Skip single underscore, only if it is part of a number
} else if (string_to_c) {
imag_start = imag_end = nullptr;
state = State::Finished;
} else {
Expand All @@ -252,9 +253,11 @@ Value KernelModule::Complex(Env *env, StringObject *input, bool exception, bool
} else if (*c == '/') {
// TODO: Parse fraction
return NilObject::the();
} else if (*c == 'e') {
// TODO: Parse scientific notation
return NilObject::the();
} else if (*c == 'e' || *c == 'E') {
if (*curr_type == Type::Scientific)
return error();
*curr_type = Type::Scientific;
*curr_end = c;
} else if (*c == '@') {
// TODO: Parse polar form
return NilObject::the();
Expand Down Expand Up @@ -308,6 +311,7 @@ Value KernelModule::Complex(Env *env, StringObject *input, bool exception, bool
new_real = Integer(env, tmp);
break;
case Type::Float:
case Type::Scientific:
new_real = Float(env, tmp);
break;
case Type::Undefined:
Expand All @@ -321,6 +325,7 @@ Value KernelModule::Complex(Env *env, StringObject *input, bool exception, bool
new_imag = Integer(env, tmp);
break;
case Type::Float:
case Type::Scientific:
new_imag = Float(env, tmp);
break;
case Type::Undefined:
Expand Down
6 changes: 6 additions & 0 deletions test/natalie/kernel_complex_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,10 @@
-> { Complex('1.0.') }.should raise_error(ArgumentError, 'invalid value for convert(): "1.0."')
-> { Complex('1..0') }.should raise_error(ArgumentError, 'invalid value for convert(): "1..0"')
end

it "accepts an 'e' only once per numeric part" do
-> { Complex('1e2e3') }.should raise_error(ArgumentError, 'invalid value for convert(): "1e2e3"')
-> { Complex('1e2e3+1i') }.should raise_error(ArgumentError, 'invalid value for convert(): "1e2e3+1i"')
-> { Complex('1+1e2e3i') }.should raise_error(ArgumentError, 'invalid value for convert(): "1+1e2e3i"')
end
end

0 comments on commit 18e1379

Please sign in to comment.