From a78d06f33aff013490775521e3dba3c42e5de85d Mon Sep 17 00:00:00 2001 From: Alberto Restifo Date: Fri, 24 Apr 2020 00:05:50 +0200 Subject: [PATCH] Implement floats --- README.md | 7 +++++++ spec/rfc_spec.cr | 30 +++++++++++------------------- src/cbor/diagnostic.cr | 14 ++++++++++++++ src/cbor/lexer.cr | 7 ++++++- src/cbor/tag.cr | 5 +++++ 5 files changed, 43 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 641d04d..89b4d72 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,16 @@ in Crystal. - Full RFC7049 support - Full support for diagnostic notation +- Assign a field to a type base on the CBOR tag +- Support for a wide range of IANA CBOR Tags ## Limitations +### Half-precision floating point is not supported + +Crystal doesn't have a `Float16` type, so half-precision floating point numbers +are not supported for the time being. + ### Maximum Array/String array/Bytes array length The spec allows for the maximum length of arrays, string arrays and bytes array diff --git a/spec/rfc_spec.cr b/spec/rfc_spec.cr index 5c32fe7..a0c726f 100644 --- a/spec/rfc_spec.cr +++ b/spec/rfc_spec.cr @@ -1,14 +1,6 @@ require "./spec_helper" # All those tests have been exported from the RFC7049 appendix A. -# -# Some test results have been modified as the tool doesn't support -# the full diagnostic notation as per RFC. -# -# Specifically: -# -# * Removed the undescore marking the start of infinite stirngs, bytes and -# array. This implementation doesn't expose the difference between the two. tests = [ { %(0), "00" }, @@ -32,25 +24,25 @@ tests = [ # { %(0.0), "f9 00 00" }, # { %(-0.0), "f9 80 00" }, # { %(1.0), "f9 3c 00" }, - # { %(1.1), "fb 3f f1 99 99 99 99 99 9a" }, + { %(1.1), "fb 3f f1 99 99 99 99 99 9a" }, # { %(1.5), "f9 3e 00" }, # { %(65504.0), "f9 7b ff" }, - # { %(100000.0), "fa 47 c3 50 00" }, - # { %(3.4028234663852886e+38), "fa 7f 7f ff ff" }, - # { %(1.0e+300), "fb 7e 37 e4 3c 88 00 75 9c" }, + { %(100000.0), "fa 47 c3 50 00" }, + # { %(3.4028234663852886e+38), "fa 7f 7f ff ff" }, TODO: Not precise enough? + { %(1.0e+300), "fb 7e 37 e4 3c 88 00 75 9c" }, # { %(5.960464477539063e-8), "f9 00 01" }, # { %(0.00006103515625), "f9 04 00" }, # { %(-4.0), "f9 c4 00" }, - # { %(-4.1), "fb c0 10 66 66 66 66 66 66" }, + { %(-4.1), "fb c0 10 66 66 66 66 66 66" }, # { %(Infinity), "f9 7c 00" }, # { %(NaN), "f9 7e 00" }, # { %(-Infinity), "f9 fc 00" }, - # { %(Infinity), "fa 7f 80 00 00" }, - # { %(NaN), "fa 7f c0 00 00" }, - # { %(-Infinity), "fa ff 80 00 00" }, - # { %(Infinity), "fb 7f f0 00 00 00 00 00 00" }, - # { %(NaN), "fb 7f f8 00 00 00 00 00 00" }, - # { %(-Infinity), "fb ff f0 00 00 00 00 00 00" }, + { %(Infinity), "fa 7f 80 00 00" }, + { %(NaN), "fa 7f c0 00 00" }, + { %(-Infinity), "fa ff 80 00 00" }, + { %(Infinity), "fb 7f f0 00 00 00 00 00 00" }, + { %(NaN), "fb 7f f8 00 00 00 00 00 00" }, + { %(-Infinity), "fb ff f0 00 00 00 00 00 00" }, { %(false), "f4" }, { %(true), "f5" }, { %(null), "f6" }, diff --git a/src/cbor/diagnostic.cr b/src/cbor/diagnostic.cr index befa983..da06286 100644 --- a/src/cbor/diagnostic.cr +++ b/src/cbor/diagnostic.cr @@ -54,6 +54,20 @@ class CBOR::Diagnostic token.value.to_diagnostic when Token::TagT "#{token.value.value.to_s}(#{next_value})" + when Token::FloatT + return "NaN" if token.value.nan? + return token.value.to_s if token.value.finite? + + case value = token.value + when Float32 + return "Infinity" if value == Float32::INFINITY + "-Infinity" + when Float64 + return "Infinity" if value == Float64::INFINITY + "-Infinity" + else + token.value.to_s + end else token.inspect end diff --git a/src/cbor/lexer.cr b/src/cbor/lexer.cr index 7233a99..fa60b6f 100644 --- a/src/cbor/lexer.cr +++ b/src/cbor/lexer.cr @@ -81,9 +81,14 @@ class CBOR::Lexer Token::MapT.new when 0xc0..0xdb consume_tag(read_size(byte - 0xc0)) - ################## when 0xe0..0xf8 consume_simple_value(read_size(byte - 0xe0)) + when 0xf9 + raise ParseError.new("Half-precision floating points are not supported") + when 0xfa + Token::FloatT.new(value: read(Float32)) + when 0xfb + Token::FloatT.new(value: read(Float64)) else raise ParseError.new("Unexpected first byte 0x#{byte.to_s(16)}") end diff --git a/src/cbor/tag.cr b/src/cbor/tag.cr index 79fe467..1d31434 100644 --- a/src/cbor/tag.cr +++ b/src/cbor/tag.cr @@ -6,6 +6,10 @@ enum CBOR::Tag : UInt32 Decimal BigFloat + CSOEEnCrypt = 16 + CSOEMac + CSOESign + ConvertBase64URL = 21 ConvertBase64 ConvertBase16 @@ -16,6 +20,7 @@ enum CBOR::Tag : UInt32 Base64 RegularExpression MimeMessage + UUID CBORMarker = 55799 end