Fix type promotion on numeric operations with derived datatypes
This commit is contained in:
parent
22c2aaa1af
commit
fa130bf14e
2 changed files with 245 additions and 20 deletions
|
@ -535,30 +535,56 @@ defmodule RDF.XSD.Numeric do
|
|||
end
|
||||
end
|
||||
|
||||
defp type_conversion(%XSD.Decimal{} = left_decimal, %{value: right_value}, XSD.Decimal),
|
||||
do: {left_decimal, XSD.Decimal.new(right_value).literal}
|
||||
defp type_conversion(left, right, XSD.Decimal) do
|
||||
{
|
||||
if XSD.Decimal.datatype?(left) do
|
||||
left
|
||||
else
|
||||
XSD.Decimal.new(left.value).literal
|
||||
end,
|
||||
if XSD.Decimal.datatype?(right) do
|
||||
right
|
||||
else
|
||||
XSD.Decimal.new(right.value).literal
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
defp type_conversion(%{value: left_value}, %XSD.Decimal{} = right_decimal, XSD.Decimal),
|
||||
do: {XSD.Decimal.new(left_value).literal, right_decimal}
|
||||
|
||||
defp type_conversion(%XSD.Decimal{value: left_decimal}, right, datatype)
|
||||
when datatype in [XSD.Double, XSD.Float],
|
||||
do: {(left_decimal |> D.to_float() |> XSD.Double.new()).literal, right}
|
||||
|
||||
defp type_conversion(left, %XSD.Decimal{value: right_decimal}, datatype)
|
||||
when datatype in [XSD.Double, XSD.Float],
|
||||
do: {left, (right_decimal |> D.to_float() |> XSD.Double.new()).literal}
|
||||
defp type_conversion(left, right, datatype) when datatype in [XSD.Double, XSD.Float] do
|
||||
{
|
||||
if XSD.Decimal.datatype?(left) do
|
||||
(left.value |> D.to_float() |> XSD.Double.new()).literal
|
||||
else
|
||||
left
|
||||
end,
|
||||
if XSD.Decimal.datatype?(right) do
|
||||
(right.value |> D.to_float() |> XSD.Double.new()).literal
|
||||
else
|
||||
right
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
defp type_conversion(left, right, _), do: {left, right}
|
||||
|
||||
defp result_type(_, XSD.Double, _), do: XSD.Double
|
||||
defp result_type(_, _, XSD.Double), do: XSD.Double
|
||||
defp result_type(_, XSD.Float, _), do: XSD.Float
|
||||
defp result_type(_, _, XSD.Float), do: XSD.Float
|
||||
defp result_type(_, XSD.Decimal, _), do: XSD.Decimal
|
||||
defp result_type(_, _, XSD.Decimal), do: XSD.Decimal
|
||||
defp result_type(:/, _, _), do: XSD.Decimal
|
||||
defp result_type(_, _, _), do: XSD.Integer
|
||||
@doc false
|
||||
def result_type(op, left, right), do: do_result_type(op, base_primitive(left), base_primitive(right))
|
||||
|
||||
defp do_result_type(_, XSD.Double, _), do: XSD.Double
|
||||
defp do_result_type(_, _, XSD.Double), do: XSD.Double
|
||||
defp do_result_type(_, XSD.Float, _), do: XSD.Float
|
||||
defp do_result_type(_, _, XSD.Float), do: XSD.Float
|
||||
defp do_result_type(_, XSD.Decimal, _), do: XSD.Decimal
|
||||
defp do_result_type(_, _, XSD.Decimal), do: XSD.Decimal
|
||||
defp do_result_type(:/, _, _), do: XSD.Decimal
|
||||
defp do_result_type(_, _, _), do: XSD.Integer
|
||||
|
||||
defp base_primitive(datatype) do
|
||||
primitive = datatype.base_primitive()
|
||||
if primitive == XSD.Double and XSD.Float.datatype?(datatype),
|
||||
do: XSD.Float,
|
||||
else: primitive
|
||||
end
|
||||
|
||||
defp literal(value), do: %Literal{literal: value}
|
||||
end
|
||||
|
|
|
@ -70,6 +70,8 @@ defmodule RDF.XSD.NumericTest do
|
|||
assert Numeric.add(XSD.decimal(1.1), XSD.positiveInteger(2)) == XSD.decimal(3.1)
|
||||
assert Numeric.add(XSD.decimal(1.1), Age.new(2)) == XSD.decimal(3.1)
|
||||
assert Numeric.add(XSD.positiveInteger(2), XSD.decimal(1.1)) == XSD.decimal(3.1)
|
||||
assert Numeric.add(XSD.decimal(1.5), Age.new(3)) == XSD.decimal(4.5)
|
||||
assert Numeric.add(DecimalUnitInterval.new(0.5), Age.new(3)) == XSD.decimal(3.5)
|
||||
end
|
||||
|
||||
test "xsd:double literal + xsd:integer literal" do
|
||||
|
@ -80,24 +82,42 @@ defmodule RDF.XSD.NumericTest do
|
|||
assert result = %RDF.Literal{literal: %XSD.Double{}} = Numeric.add(XSD.double(1.1), Age.new(2))
|
||||
assert_in_delta RDF.Literal.value(result),
|
||||
RDF.Literal.value(XSD.double(3.1)), 0.000000000000001
|
||||
|
||||
assert result = %RDF.Literal{literal: %XSD.Double{}} = Numeric.add(DoubleUnitInterval.new(0.5), Age.new(2))
|
||||
assert_in_delta RDF.Literal.value(result),
|
||||
RDF.Literal.value(XSD.double(2.5)), 0.000000000000001
|
||||
end
|
||||
|
||||
test "xsd:decimal literal + xsd:double literal" do
|
||||
assert result = %RDF.Literal{literal: %XSD.Double{}} = Numeric.add(XSD.decimal(1.1), XSD.double(2.2))
|
||||
assert_in_delta RDF.Literal.value(result),
|
||||
RDF.Literal.value(XSD.double(3.3)), 0.000000000000001
|
||||
|
||||
assert result = %RDF.Literal{literal: %XSD.Double{}} =
|
||||
Numeric.add(DecimalUnitInterval.new(0.5), DoubleUnitInterval.new(0.5))
|
||||
assert_in_delta RDF.Literal.value(result),
|
||||
RDF.Literal.value(XSD.double(1.0)), 0.000000000000001
|
||||
end
|
||||
|
||||
test "xsd:float literal + xsd:integer literal" do
|
||||
assert result = %RDF.Literal{literal: %XSD.Float{}} = Numeric.add(XSD.float(1.1), XSD.integer(2))
|
||||
assert_in_delta RDF.Literal.value(result),
|
||||
RDF.Literal.value(XSD.float(3.1)), 0.000000000000001
|
||||
assert result = %RDF.Literal{literal: %XSD.Float{}} =
|
||||
Numeric.add(Age.new(42), FloatUnitInterval.new(0.5))
|
||||
assert_in_delta RDF.Literal.value(result),
|
||||
RDF.Literal.value(XSD.float(42.5)), 0.000000000000001
|
||||
end
|
||||
|
||||
test "xsd:decimal literal + xsd:float literal" do
|
||||
assert result = %RDF.Literal{literal: %XSD.Float{}} = Numeric.add(XSD.decimal(1.1), XSD.float(2.2))
|
||||
assert_in_delta RDF.Literal.value(result),
|
||||
RDF.Literal.value(XSD.float(3.3)), 0.000000000000001
|
||||
|
||||
assert result = %RDF.Literal{literal: %XSD.Float{}} =
|
||||
Numeric.add(DecimalUnitInterval.new(0.5), FloatUnitInterval.new(0.5))
|
||||
assert_in_delta RDF.Literal.value(result),
|
||||
RDF.Literal.value(XSD.float(1.0)), 0.000000000000001
|
||||
end
|
||||
|
||||
test "if one of the operands is a zero or a finite number and the other is INF or -INF, INF or -INF is returned" do
|
||||
|
@ -264,6 +284,7 @@ defmodule RDF.XSD.NumericTest do
|
|||
test "xsd:integer literal / xsd:integer literal" do
|
||||
assert Numeric.divide(XSD.integer(4), XSD.integer(2)) == XSD.decimal(2.0)
|
||||
assert Numeric.divide(XSD.integer(4), Age.new(2)) == XSD.decimal(2.0)
|
||||
assert Numeric.divide(Age.new(4), Age.new(2)) == XSD.decimal(2.0)
|
||||
end
|
||||
|
||||
test "xsd:decimal literal / xsd:integer literal" do
|
||||
|
@ -619,4 +640,182 @@ defmodule RDF.XSD.NumericTest do
|
|||
assert Numeric.floor(:foo) == nil
|
||||
end
|
||||
end
|
||||
|
||||
test "result_type/3 (type-promotion)" do
|
||||
%{
|
||||
XSD.Integer => %{
|
||||
XSD.Integer => XSD.Integer,
|
||||
XSD.NonPositiveInteger => XSD.Integer,
|
||||
XSD.NegativeInteger => XSD.Integer,
|
||||
XSD.Long => XSD.Integer,
|
||||
XSD.Int => XSD.Integer,
|
||||
XSD.Short => XSD.Integer,
|
||||
XSD.Byte => XSD.Integer,
|
||||
XSD.NonNegativeInteger => XSD.Integer,
|
||||
XSD.UnsignedLong => XSD.Integer,
|
||||
XSD.UnsignedInt => XSD.Integer,
|
||||
XSD.UnsignedShort => XSD.Integer,
|
||||
XSD.UnsignedByte => XSD.Integer,
|
||||
XSD.PositiveInteger => XSD.Integer,
|
||||
XSD.Decimal => XSD.Decimal,
|
||||
XSD.Float => XSD.Float,
|
||||
XSD.Double => XSD.Double,
|
||||
DecimalUnitInterval => XSD.Decimal,
|
||||
FloatUnitInterval => XSD.Float,
|
||||
DoubleUnitInterval => XSD.Double,
|
||||
},
|
||||
XSD.Byte => %{
|
||||
XSD.Integer => XSD.Integer,
|
||||
XSD.NonPositiveInteger => XSD.Integer,
|
||||
XSD.NegativeInteger => XSD.Integer,
|
||||
XSD.Long => XSD.Integer,
|
||||
XSD.Int => XSD.Integer,
|
||||
XSD.Short => XSD.Integer,
|
||||
XSD.Byte => XSD.Integer,
|
||||
XSD.NonNegativeInteger => XSD.Integer,
|
||||
XSD.UnsignedLong => XSD.Integer,
|
||||
XSD.UnsignedInt => XSD.Integer,
|
||||
XSD.UnsignedShort => XSD.Integer,
|
||||
XSD.UnsignedByte => XSD.Integer,
|
||||
XSD.PositiveInteger => XSD.Integer,
|
||||
XSD.Decimal => XSD.Decimal,
|
||||
XSD.Float => XSD.Float,
|
||||
XSD.Double => XSD.Double,
|
||||
DecimalUnitInterval => XSD.Decimal,
|
||||
FloatUnitInterval => XSD.Float,
|
||||
DoubleUnitInterval => XSD.Double,
|
||||
},
|
||||
XSD.Decimal => %{
|
||||
XSD.Integer => XSD.Decimal,
|
||||
XSD.NonPositiveInteger => XSD.Decimal,
|
||||
XSD.NegativeInteger => XSD.Decimal,
|
||||
XSD.Long => XSD.Decimal,
|
||||
XSD.Int => XSD.Decimal,
|
||||
XSD.Short => XSD.Decimal,
|
||||
XSD.Byte => XSD.Decimal,
|
||||
XSD.NonNegativeInteger => XSD.Decimal,
|
||||
XSD.UnsignedLong => XSD.Decimal,
|
||||
XSD.UnsignedInt => XSD.Decimal,
|
||||
XSD.UnsignedShort => XSD.Decimal,
|
||||
XSD.UnsignedByte => XSD.Decimal,
|
||||
XSD.PositiveInteger => XSD.Decimal,
|
||||
XSD.Decimal => XSD.Decimal,
|
||||
XSD.Float => XSD.Float,
|
||||
XSD.Double => XSD.Double,
|
||||
DecimalUnitInterval => XSD.Decimal,
|
||||
FloatUnitInterval => XSD.Float,
|
||||
DoubleUnitInterval => XSD.Double,
|
||||
},
|
||||
DecimalUnitInterval => %{
|
||||
XSD.Integer => XSD.Decimal,
|
||||
XSD.NonPositiveInteger => XSD.Decimal,
|
||||
XSD.NegativeInteger => XSD.Decimal,
|
||||
XSD.Long => XSD.Decimal,
|
||||
XSD.Int => XSD.Decimal,
|
||||
XSD.Short => XSD.Decimal,
|
||||
XSD.Byte => XSD.Decimal,
|
||||
XSD.NonNegativeInteger => XSD.Decimal,
|
||||
XSD.UnsignedLong => XSD.Decimal,
|
||||
XSD.UnsignedInt => XSD.Decimal,
|
||||
XSD.UnsignedShort => XSD.Decimal,
|
||||
XSD.UnsignedByte => XSD.Decimal,
|
||||
XSD.PositiveInteger => XSD.Decimal,
|
||||
XSD.Decimal => XSD.Decimal,
|
||||
XSD.Float => XSD.Float,
|
||||
XSD.Double => XSD.Double,
|
||||
DecimalUnitInterval => XSD.Decimal,
|
||||
FloatUnitInterval => XSD.Float,
|
||||
DoubleUnitInterval => XSD.Double,
|
||||
},
|
||||
XSD.Float => %{
|
||||
XSD.Integer => XSD.Float,
|
||||
XSD.NonPositiveInteger => XSD.Float,
|
||||
XSD.NegativeInteger => XSD.Float,
|
||||
XSD.Long => XSD.Float,
|
||||
XSD.Int => XSD.Float,
|
||||
XSD.Short => XSD.Float,
|
||||
XSD.Byte => XSD.Float,
|
||||
XSD.NonNegativeInteger => XSD.Float,
|
||||
XSD.UnsignedLong => XSD.Float,
|
||||
XSD.UnsignedInt => XSD.Float,
|
||||
XSD.UnsignedShort => XSD.Float,
|
||||
XSD.UnsignedByte => XSD.Float,
|
||||
XSD.PositiveInteger => XSD.Float,
|
||||
XSD.Decimal => XSD.Float,
|
||||
XSD.Float => XSD.Float,
|
||||
XSD.Double => XSD.Double,
|
||||
DecimalUnitInterval => XSD.Float,
|
||||
FloatUnitInterval => XSD.Float,
|
||||
DoubleUnitInterval => XSD.Double,
|
||||
},
|
||||
FloatUnitInterval => %{
|
||||
XSD.Integer => XSD.Float,
|
||||
XSD.NonPositiveInteger => XSD.Float,
|
||||
XSD.NegativeInteger => XSD.Float,
|
||||
XSD.Long => XSD.Float,
|
||||
XSD.Int => XSD.Float,
|
||||
XSD.Short => XSD.Float,
|
||||
XSD.Byte => XSD.Float,
|
||||
XSD.NonNegativeInteger => XSD.Float,
|
||||
XSD.UnsignedLong => XSD.Float,
|
||||
XSD.UnsignedInt => XSD.Float,
|
||||
XSD.UnsignedShort => XSD.Float,
|
||||
XSD.UnsignedByte => XSD.Float,
|
||||
XSD.PositiveInteger => XSD.Float,
|
||||
XSD.Decimal => XSD.Float,
|
||||
XSD.Float => XSD.Float,
|
||||
XSD.Double => XSD.Double,
|
||||
DecimalUnitInterval => XSD.Float,
|
||||
FloatUnitInterval => XSD.Float,
|
||||
DoubleUnitInterval => XSD.Double,
|
||||
},
|
||||
XSD.Double => %{
|
||||
XSD.Integer => XSD.Double,
|
||||
XSD.NonPositiveInteger => XSD.Double,
|
||||
XSD.NegativeInteger => XSD.Double,
|
||||
XSD.Long => XSD.Double,
|
||||
XSD.Int => XSD.Double,
|
||||
XSD.Short => XSD.Double,
|
||||
XSD.Byte => XSD.Double,
|
||||
XSD.NonNegativeInteger => XSD.Double,
|
||||
XSD.UnsignedLong => XSD.Double,
|
||||
XSD.UnsignedInt => XSD.Double,
|
||||
XSD.UnsignedShort => XSD.Double,
|
||||
XSD.UnsignedByte => XSD.Double,
|
||||
XSD.PositiveInteger => XSD.Double,
|
||||
XSD.Decimal => XSD.Double,
|
||||
XSD.Float => XSD.Double,
|
||||
XSD.Double => XSD.Double,
|
||||
DecimalUnitInterval => XSD.Double,
|
||||
FloatUnitInterval => XSD.Double,
|
||||
DoubleUnitInterval => XSD.Double,
|
||||
},
|
||||
DoubleUnitInterval => %{
|
||||
XSD.Integer => XSD.Double,
|
||||
XSD.NonPositiveInteger => XSD.Double,
|
||||
XSD.NegativeInteger => XSD.Double,
|
||||
XSD.Long => XSD.Double,
|
||||
XSD.Int => XSD.Double,
|
||||
XSD.Short => XSD.Double,
|
||||
XSD.Byte => XSD.Double,
|
||||
XSD.NonNegativeInteger => XSD.Double,
|
||||
XSD.UnsignedLong => XSD.Double,
|
||||
XSD.UnsignedInt => XSD.Double,
|
||||
XSD.UnsignedShort => XSD.Double,
|
||||
XSD.UnsignedByte => XSD.Double,
|
||||
XSD.PositiveInteger => XSD.Double,
|
||||
XSD.Decimal => XSD.Double,
|
||||
XSD.Float => XSD.Double,
|
||||
XSD.Double => XSD.Double,
|
||||
DecimalUnitInterval => XSD.Double,
|
||||
FloatUnitInterval => XSD.Double,
|
||||
DoubleUnitInterval => XSD.Double,
|
||||
},
|
||||
}
|
||||
|> Enum.each(fn {left, right_result} ->
|
||||
Enum.each(right_result, fn {right, result} ->
|
||||
assert Numeric.result_type(:+, left, right) == result
|
||||
end)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue