crystal-cbor/src/cbor/lexer.cr

117 lines
2.4 KiB
Crystal
Raw Normal View History

2020-04-17 14:32:43 +02:00
require "./token"
class CBOR::Lexer
2020-04-19 00:18:54 +02:00
def self.new(string : String)
new IO::Memory.new(string)
end
def self.new(slice : Bytes)
new IO::Memory.new(slice)
end
@token : Token::T
2020-04-17 14:32:43 +02:00
def initialize(@io : IO)
2020-04-19 00:18:54 +02:00
@byte_number = 0
@current_byte_number = 0
@token = Token::NullT.new(0)
@token_finished = true
2020-04-17 14:32:43 +02:00
end
2020-04-19 00:18:54 +02:00
@[AlwaysInline]
def current_token : Token::T
if @token_finished
@token_finished = false
@token = next_token
else
@token
end
end
2020-04-17 14:32:43 +02:00
2020-04-19 00:18:54 +02:00
@[AlwaysInline]
def finish_token!
@token_finished = true
end
2020-04-17 14:32:43 +02:00
2020-04-19 00:18:54 +02:00
@[AlwaysInline]
def read_token : Token::T
if @token_finished
@token = next_token
else
finish_token!
end
@token
end
private def next_token
@current_byte_number = @byte_number
current_byte = next_byte
case current_byte
when 0x00..0x17
consume_int(current_byte)
2020-04-17 14:32:43 +02:00
when 0x18
2020-04-19 12:16:05 +02:00
consume_int(read(UInt8))
2020-04-17 19:50:26 +02:00
when 0x19
2020-04-19 12:16:05 +02:00
consume_int(read(UInt16))
2020-04-17 19:50:26 +02:00
when 0x1a
2020-04-19 12:16:05 +02:00
consume_int(read(UInt32))
2020-04-17 19:50:26 +02:00
when 0x1b
2020-04-19 12:16:05 +02:00
consume_int(read(UInt64))
2020-04-19 00:18:54 +02:00
when 0x20..0x37
2020-04-19 12:16:05 +02:00
# This range represents values from -1..-24 so we subtract 0x20
# from the uint8 value to
consume_int(to_negative_int(current_byte.to_u8 - 0x20))
2020-04-19 00:18:54 +02:00
when 0x38
2020-04-19 12:16:05 +02:00
consume_int(to_negative_int(read(UInt8)))
2020-04-19 00:18:54 +02:00
when 0x39
2020-04-19 12:16:05 +02:00
consume_int(to_negative_int(read(UInt16)))
2020-04-19 00:18:54 +02:00
when 0x3a
2020-04-19 12:16:05 +02:00
consume_int(to_negative_int(read(UInt32)))
2020-04-19 00:18:54 +02:00
when 0x3b
2020-04-19 12:16:05 +02:00
consume_int(to_negative_int(read(UInt64)))
else
fail
2020-04-17 14:32:43 +02:00
end
end
2020-04-19 12:16:05 +02:00
private def next_byte : UInt8
2020-04-17 14:32:43 +02:00
byte = @io.read_byte
2020-04-19 00:18:54 +02:00
@byte_number += 1
fail unless byte
byte
2020-04-17 14:32:43 +02:00
end
2020-04-19 00:18:54 +02:00
private def consume_int(value)
Token::IntT.new(@current_byte_number, value)
2020-04-17 19:50:26 +02:00
end
2020-04-19 12:16:05 +02:00
{% begin %}
{% uints = %w(UInt8 UInt16 UInt32 UInt64) %}
{% conv = %w(to_i8 to_i16 to_i32 to_i64 to_i128) %}
{% for uint, index in uints %}
# Reads the `{{uint.id}}` as a negative integer, returning the samllest
# integer capable of containing the value.
def to_negative_int(value : {{uint.id}})
int = begin
-value.{{conv[index].id}}
rescue OverflowError
-value.{{conv[index + 1].id}}
end
int - 1
end
{% end %}
{% end %}
2020-04-17 19:50:26 +02:00
2020-04-19 00:18:54 +02:00
private def read(type : T.class) forall T
@byte_number += sizeof(T)
@io.read_bytes(T, IO::ByteFormat::NetworkEndian)
2020-04-17 19:50:26 +02:00
end
2020-04-19 00:18:54 +02:00
private def fail
raise "Pase error"
2020-04-17 14:32:43 +02:00
end
end