Add support for string streaming
parent
321b3fd986
commit
28f9cfa1f5
|
@ -73,7 +73,7 @@ tests = [
|
||||||
# { %(["a", {"b": "c"}]), "82 61 61 a1 61 62 61 63" },
|
# { %(["a", {"b": "c"}]), "82 61 61 a1 61 62 61 63" },
|
||||||
# { %({"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}), "a5 61 61 61 41 61 62 61 42 61 63 61 43 61 64 61 44 61 65 61 45" },
|
# { %({"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}), "a5 61 61 61 41 61 62 61 42 61 63 61 43 61 64 61 44 61 65 61 45" },
|
||||||
{ %((_ h'0102', h'030405')), "5f 42 01 02 43 03 04 05 ff" },
|
{ %((_ h'0102', h'030405')), "5f 42 01 02 43 03 04 05 ff" },
|
||||||
# { %((_ "strea", "ming")), "7f 65 73 74 72 65 61 64 6d 69 6e 67 ff" },
|
{ %((_ "strea", "ming")), "7f 65 73 74 72 65 61 64 6d 69 6e 67 ff" },
|
||||||
# { %([_ ]), "9f ff" },
|
# { %([_ ]), "9f ff" },
|
||||||
# { %([_ 1, [2, 3], [_ 4, 5]]), "9f 01 82 02 03 9f 04 05 ff ff" },
|
# { %([_ 1, [2, 3], [_ 4, 5]]), "9f 01 82 02 03 9f 04 05 ff ff" },
|
||||||
# { %([_ 1, [2, 3], [4, 5]]), "9f 01 82 02 03 82 04 05 ff" },
|
# { %([_ 1, [2, 3], [4, 5]]), "9f 01 82 02 03 82 04 05 ff" },
|
||||||
|
|
|
@ -19,6 +19,5 @@ module CBOR
|
||||||
UInt32 |
|
UInt32 |
|
||||||
Int64 |
|
Int64 |
|
||||||
UInt64 |
|
UInt64 |
|
||||||
Int128 |
|
Int128
|
||||||
BytesArray
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,6 +34,8 @@ class CBOR::Diagnostic
|
||||||
"h'#{token[:value].as(Bytes).hexstring}'"
|
"h'#{token[:value].as(Bytes).hexstring}'"
|
||||||
when Kind::BytesArray
|
when Kind::BytesArray
|
||||||
token[:value].as(BytesArray).to_diagnostic
|
token[:value].as(BytesArray).to_diagnostic
|
||||||
|
when Kind::StringArray
|
||||||
|
token[:value].as(StringArray).to_diagnostic
|
||||||
else
|
else
|
||||||
token[:kind].to_s
|
token[:kind].to_s
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,25 @@
|
||||||
require "./token"
|
require "./token"
|
||||||
|
|
||||||
class CBOR::Lexer
|
class CBOR::Lexer
|
||||||
|
# Types returned by the lexer
|
||||||
|
alias Type = Nil |
|
||||||
|
Bool |
|
||||||
|
String |
|
||||||
|
Bytes |
|
||||||
|
Array(Type) |
|
||||||
|
Hash(Type, Type) |
|
||||||
|
Int8 |
|
||||||
|
UInt8 |
|
||||||
|
Int16 |
|
||||||
|
UInt16 |
|
||||||
|
Int32 |
|
||||||
|
UInt32 |
|
||||||
|
Int64 |
|
||||||
|
UInt64 |
|
||||||
|
Int128 |
|
||||||
|
BytesArray |
|
||||||
|
StringArray
|
||||||
|
|
||||||
def self.new(string : String)
|
def self.new(string : String)
|
||||||
new IO::Memory.new(string)
|
new IO::Memory.new(string)
|
||||||
end
|
end
|
||||||
|
@ -47,6 +66,8 @@ class CBOR::Lexer
|
||||||
{kind: token[:kind], value: nil}
|
{kind: token[:kind], value: nil}
|
||||||
when Kind::BytesArray
|
when Kind::BytesArray
|
||||||
{kind: token[:kind], value: read_bytes_array}
|
{kind: token[:kind], value: read_bytes_array}
|
||||||
|
when Kind::StringArray
|
||||||
|
{kind: token[:kind], value: read_string_array}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -54,17 +75,24 @@ class CBOR::Lexer
|
||||||
def read_bytes_array : CBOR::BytesArray
|
def read_bytes_array : CBOR::BytesArray
|
||||||
bytes = BytesArray.new
|
bytes = BytesArray.new
|
||||||
|
|
||||||
loop do
|
read_until(Kind::BytesArrayEnd, only: Kind::Bytes) do |chunk|
|
||||||
token = next_token
|
bytes << chunk.as(Bytes)
|
||||||
raise ParseError.new("Unexpected EOF while reading bytes array") unless token
|
|
||||||
break if token[:kind] == Kind::BytesArrayEnd
|
|
||||||
raise ParseError.new("Illegal token #{token.class} while reading bytes array") unless token[:kind] == Kind::Bytes
|
|
||||||
bytes << token[:value].as(Bytes)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
bytes
|
bytes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Reads until break for chunks of strings
|
||||||
|
def read_string_array : CBOR::StringArray
|
||||||
|
strings = StringArray.new
|
||||||
|
|
||||||
|
read_until(Kind::StringArrayEnd, only: Kind::String) do |chunk|
|
||||||
|
strings << chunk.as(String)
|
||||||
|
end
|
||||||
|
|
||||||
|
strings
|
||||||
|
end
|
||||||
|
|
||||||
private def next_token : Token?
|
private def next_token : Token?
|
||||||
return nil if @eof
|
return nil if @eof
|
||||||
|
|
||||||
|
@ -118,6 +146,8 @@ class CBOR::Lexer
|
||||||
consume_string(read(UInt32))
|
consume_string(read(UInt32))
|
||||||
when 0x7b
|
when 0x7b
|
||||||
consume_string(read(UInt16))
|
consume_string(read(UInt16))
|
||||||
|
when 0x7f
|
||||||
|
{kind: open_token(Kind::StringArray), value: nil}
|
||||||
when 0xff
|
when 0xff
|
||||||
{kind: finish_token, value: nil}
|
{kind: finish_token, value: nil}
|
||||||
else
|
else
|
||||||
|
@ -125,6 +155,22 @@ class CBOR::Lexer
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Reads tokens until it meets the stop kind.
|
||||||
|
# Optionally it can fail when the read token is not of the passed kind.
|
||||||
|
private def read_until(stop : Kind, only : Kind?, &block)
|
||||||
|
loop do
|
||||||
|
token = next_token
|
||||||
|
raise ParseError.new("Unexpected EOF") unless token
|
||||||
|
break if token[:kind] == stop
|
||||||
|
|
||||||
|
if only && token[:kind] != only
|
||||||
|
raise ParseError.new("Illegal token #{token[:kind].to_s} while reading #{only.to_s} array")
|
||||||
|
end
|
||||||
|
|
||||||
|
yield token[:value]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private def next_byte : UInt8?
|
private def next_byte : UInt8?
|
||||||
byte = @io.read_byte
|
byte = @io.read_byte
|
||||||
if byte
|
if byte
|
||||||
|
|
|
@ -15,4 +15,4 @@ enum CBOR::Kind
|
||||||
Map
|
Map
|
||||||
end
|
end
|
||||||
|
|
||||||
alias CBOR::Token = NamedTuple(kind: Kind, value: Type)
|
alias CBOR::Token = NamedTuple(kind: Kind, value: Lexer::Type)
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
class CBOR::StringArray < Array(String)
|
||||||
|
def to_s : String
|
||||||
|
join
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_diagnostic : String
|
||||||
|
"(_ #{map { |s| quote(s) }.join(", ")})"
|
||||||
|
end
|
||||||
|
|
||||||
|
private def quote(chunk : String) : String
|
||||||
|
%("#{chunk}")
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue