Add support for terminating tokens

dev
Alberto Restifo 2020-04-21 00:01:35 +02:00
parent 2e2edd1908
commit 56eed66541
3 changed files with 49 additions and 21 deletions

View File

@ -6,7 +6,6 @@ require "./token"
# provided in the RFC and ensuring a correct functioning of the `CBOR::Lexer`. # provided in the RFC and ensuring a correct functioning of the `CBOR::Lexer`.
class CBOR::Diagnostic class CBOR::Diagnostic
@lexer : Lexer @lexer : Lexer
@is_array : Bool = false
def initialize(input) def initialize(input)
@lexer = Lexer.new(input) @lexer = Lexer.new(input)
@ -29,17 +28,23 @@ class CBOR::Diagnostic
return nil unless token return nil unless token
case token case token
when Token::BytesArray when Token::BytesArrayT
@is_array = true consume_bytes_array
when Token::BreakT else
@is_array = flase Token.to_diagnostic(token)
end
end end
separator + Token.to_diagnostic(token) private def consume_bytes_array : String
elements = [] of String
loop do
token = @lexer.next_token
raise "Unexpected EOF" unless token
break if token.is_a?(Token::BytesArrayEndT)
elements << Token.to_diagnostic(token)
end end
private def separator : String "(_ #{elements.join(", ")})"
return ", " if @is_array
""
end end
end end

View File

@ -1,8 +1,6 @@
require "./token" require "./token"
class CBOR::Lexer class CBOR::Lexer
BREAK = 0xff
def self.new(string : String) def self.new(string : String)
new IO::Memory.new(string) new IO::Memory.new(string)
end end
@ -13,6 +11,10 @@ class CBOR::Lexer
@current_pos : Int64 @current_pos : Int64
@eof : Bool = false @eof : Bool = false
# Holds a list of previously opened tokens.
# When a break in reached, the last entry in the array is
# the token to close.
@open_tokens = [] of Token::T
def initialize(@io : IO) def initialize(@io : IO)
@current_pos = 0 @current_pos = 0
@ -60,10 +62,9 @@ class CBOR::Lexer
when 0x5b when 0x5b
consume_binary(read(UInt64)) consume_binary(read(UInt64))
when 0x5f when 0x5f
Token::BytesArrayStartT.new(@current_pos) open_token(Token::BytesArrayT.new(@current_pos))
when 0xff when 0xff
# TODO: Define which segment it's breaking finish_token
Token::BreakT.new(@current_pos)
else else
raise ParseError.new("Unexpected first byte 0x#{current_byte.to_s(16)}") raise ParseError.new("Unexpected first byte 0x#{current_byte.to_s(16)}")
end end
@ -89,6 +90,26 @@ class CBOR::Lexer
Token::BytesT.new(@current_pos, bytes) Token::BytesT.new(@current_pos, bytes)
end end
private def open_token(token : Token::T) : Token::T
@open_tokens.push(token)
token
end
private def finish_token : Token::T
opened_token = @open_tokens.pop
case opened_token
when Token::ArrayT
Token::ArrayEndT.new(@current_pos)
when Token::BytesArrayT
Token::BytesArrayEndT.new(@current_pos)
when Token::StringArrayT
Token::StringArrayEndT.new(@current_pos)
else
raise ParseError.new("Unexpected token termination #{opened_token.class}")
end
end
# Creates a method overloaded for each UInt sizes to convert the UInt into # Creates a method overloaded for each UInt sizes to convert the UInt into
# the respective Int capable of containing the value # the respective Int capable of containing the value

View File

@ -3,28 +3,30 @@ class CBOR::Token
record UndefinedT, byte_number : Int64 record UndefinedT, byte_number : Int64
record BoolT, byte_number : Int64, value : Bool record BoolT, byte_number : Int64, value : Bool
record ArrayT, byte_number : Int64, size : UInt32? record ArrayT, byte_number : Int64, size : UInt32?
record ArrayEndT, byte_number : Int64
record MapT, byte_number : Int64, size : UInt32? record MapT, byte_number : Int64, size : UInt32?
record IntT, byte_number : Int64, value : Int8 | UInt8 | Int16 | UInt16 | Int32 | UInt32 | Int64 | UInt64 | Int128 record IntT, byte_number : Int64, value : Int8 | UInt8 | Int16 | UInt16 | Int32 | UInt32 | Int64 | UInt64 | Int128
record FloatT, byte_number : Int64, value : Float64 record FloatT, byte_number : Int64, value : Float64
record StringT, byte_number : Int64, value : String record StringT, byte_number : Int64, value : String
record BytesT, byte_number : Int64, value : Bytes record BytesT, byte_number : Int64, value : Bytes
record StringArrayStartT, byte_number : Int64 record StringArrayT, byte_number : Int64
record StringArrayEndT, byte_number : Int64 record StringArrayEndT, byte_number : Int64
record BytesArrayStartT, byte_number : Int64 record BytesArrayT, byte_number : Int64
record BytesArrayEndT, byte_number : Int64 record BytesArrayEndT, byte_number : Int64
alias T = NullT | alias T = NullT |
UndefinedT | UndefinedT |
BoolT | BoolT |
ArrayT | ArrayT |
ArrayEndT |
MapT | MapT |
IntT | IntT |
FloatT | FloatT |
StringT | StringT |
BytesT | BytesT |
StringArrayStartT | StringArrayT |
StringArrayEndT | StringArrayEndT |
BytesArrayStartT | BytesArrayT |
BytesArrayEndT BytesArrayEndT
def self.to_diagnostic(token : T) : String def self.to_diagnostic(token : T) : String
@ -40,7 +42,7 @@ class CBOR::Token
"undefined" "undefined"
when BoolT when BoolT
token.value.to_s token.value.to_s
when BytesArrayStartT when BytesArrayT
"(_ " "(_ "
when BytesArrayEndT when BytesArrayEndT
")" ")"