crystal-cbor/src/cbor/diagnostic.cr

85 lines
2.1 KiB
Crystal
Raw Normal View History

# Reads a CBOR input into a diagnostic string.
# This consumes the IO and is mostly usedful to tests again the example
# provided in the RFC and ensuring a correct functioning of the `CBOR::Lexer`.
class CBOR::Diagnostic
@lexer : Lexer
def initialize(input)
@lexer = Lexer.new(input)
end
# Reads the content of the IO and prints out a diagnostic string
# represation of the input.
def to_s : String
result = ""
2020-04-21 15:02:31 +02:00
while value = next_value
2020-04-21 22:48:27 +02:00
result += value
end
result
end
private def next_value : String?
2020-04-21 15:02:31 +02:00
token = @lexer.read_next
return nil unless token
2020-04-22 22:31:33 +02:00
to_diagnostic(token)
end
2020-04-22 22:31:33 +02:00
private def to_diagnostic(token : Token) : String
2020-04-22 11:17:06 +02:00
case token.kind
2020-04-21 22:48:27 +02:00
when Kind::Int
2020-04-22 11:17:06 +02:00
token.value.to_s
2020-04-21 23:18:56 +02:00
when Kind::String
if token.chunks
chunks = chunks(token.value.as(String), token.chunks.as(Array(Int32)))
"(_ #{chunks.map { |s| string(s) }.join(", ")})"
else
string(token.value.as(String))
end
2020-04-21 22:48:27 +02:00
when Kind::Bytes
if token.chunks
chunks = chunks(token.value.as(Bytes), token.chunks.as(Array(Int32)))
"(_ #{chunks.map { |b| bytes(b) }.join(", ")})"
else
bytes(token.value.as(Bytes))
end
2020-04-22 22:31:33 +02:00
# when Kind::Array
# value = token.value.as(Array(Type))
# return "[]" unless value.size > 0
# content = value.map { |token| to_diagnostic(token) }.join(", ")
# return "[#{content}]" if token.size
# "[_ #{content}]"
2020-04-21 00:01:35 +02:00
else
2020-04-22 11:17:06 +02:00
token.kind.to_s
end
end
private def chunks(value : Bytes, chunks : Array(Int32)) : Array(Bytes)
res = Array(Bytes).new
bytes = value.to_a
chunks.each do |size|
bytes_chunk = bytes.shift(size)
res << Bytes.new(bytes_chunk.to_unsafe, bytes_chunk.size)
end
res
end
private def chunks(value : String, chunks : Array(Int32)) : Array(String)
res = Array(String).new
arr = value.split("")
chunks.each do |size|
res << arr.shift(size).join
end
res
end
private def bytes(b : Bytes) : String
"h'#{b.hexstring}'"
end
private def string(s : String) : String
%("#{s}")
end
end