解析Ada中的json5/js对象文本



Ada新手。在一个项目中尝试使用一些对象,比如下面的{name:'Hermann',age:33},我宁愿不为此编写自己的json解析器。是否有:

  • 配置Gnatcolls.JSON以解析和写入这些对象的一种方法
  • 我可以使用一个不同的库来支持json5或javascript对象文字

在做其他事情的同时,我很快就根据规范编写了一个JSON解析器,花了一天半的时间;这不是特别难,我会考虑把它发布到github或其他什么地方。

然而,JSON5的不同之处在于,重新实现它的难度与编写某种适配器的难度相同。编辑解析器以接受新的构造可能比人们预期的更困难,因为允许IdentifierName作为关键字意味着你不能简单地将序列(1(";打开支架";,(2( ";消耗空白";,(3( ";获取字符串";,(4( ";消耗空白";,(5( ";获取冒号,(6(";消耗空白";,(7( ";获取JSON对象";,(8( ";消耗空白";,(9( ";获取字符;如果是逗号,请转到#1,否则它应该是一个大括号;。

也许有一件事可以让事情变得更容易,那就是将流和字符串操作等同起来,这样您的对象就只有一个生成方法;有三种主要方法:

  1. 制作一个generic,以便它获取一个字符串并给出流操作的配置文件。

  2. 制作一对提供相同接口的重载函数。

  3. 制作一个字符串流;以下方法可以做到这一点:

    Package Example is
    -- String_Stream allows uses a string to buffer the underlying stream,
    -- it may be initialized with content from a string or a given length for
    -- the string underlying the stream.
    --
    -- This is intended for the construction and consumption of string-data
    -- using stream-operations
    Type String_Stream(<>) is new Ada.Streams.Root_Stream_Type with Private;
    Subtype Root_Stream_Class is Ada.Streams.Root_Stream_Type'Class;
    -- Create a String_Stream.
    Function "+"( Length : Natural ) return String_Stream;
    Function "+"( Text   : String  ) return String_Stream;
    Function "+"( Length : Natural ) return not null access Root_Stream_Class;
    Function "+"( Text   : String  ) return not null access Root_Stream_Class;
    -- Retrieve the remaining string-data; the (POSITION..DATA'LENGTH) slice.
    Function "-"( Stream : String_Stream ) return String;
    -- Retrieve the string-data; the (1..DATA'LENGTH) slice.
    Function Data(Stream : String_Stream ) return String;
    Private
    Pragma Assert( Ada.Streams.Stream_Element'Size = String'Component_Size );
    Overriding
    procedure Read
    (Stream : in out String_Stream;
    Item   :    out Ada.Streams.Stream_Element_Array;
    Last   :    out Ada.Streams.Stream_Element_Offset);
    Overriding
    procedure Write
    (Stream : in out String_Stream;
    Item   :        Ada.Streams.Stream_Element_Array);
    Type String_Stream(Length : Ada.Streams.Stream_Element_Count) is
    new Ada.Streams.Root_Stream_Type with record
    Data     : Ada.Streams.Stream_Element_Array(1..Length);
    Position : Ada.Streams.Stream_Element_Count;
    End record;
    End Example;
    

实现:

Package Body Example is
Use Ada.Streams;
-------------------
--  INITALIZERS  --
-------------------
Function From_String( Text   : String  ) return String_Stream
with Inline, Pure_Function;
Function Buffer     ( Length : Natural ) return String_Stream
with Inline, Pure_Function;

--------------
--  R E A D --
--------------
Procedure Read
(Stream : in out String_Stream;
Item   :    out Ada.Streams.Stream_Element_Array;
Last   :    out Ada.Streams.Stream_Element_Offset) is
Use Ada.IO_Exceptions, Ada.Streams;
Begin
-- When there is a read of zero, do nothing.
-- When there is a read beyond the buffer's bounds, raise an exception.
--  Note: I've used two cases here-
--      1) when the read is greater than the buffer,
--      2) when the read would go beyond the buffer.
-- Finally, read the given amount of data and update the position.
if Item'Length = 0 then
null;
elsif Item'Length > Stream.Data'Length then
Raise End_Error with "Request is larger than the buffer's size.";
elsif Stream_Element_Offset'Pred(Stream.Position)+Item'Length > Stream.Data'Length then
Raise End_Error with "Buffer will over-read.";
else
Declare
Subtype Selection is Stream_Element_Offset range
Stream.Position..Stream.Position+Stream_Element_Offset'Pred(Item'Length);
Begin
Item(Item'Range):= Stream.Data(Selection);
Stream.Position:= Stream_Element_Offset'Succ(Selection'Last);
Last:= Selection'Last;--Stream.Position;
End;
end if;
End Read;

-----------------
--  W R I T E  --
-----------------
Procedure Write
(Stream : in out String_Stream;
Item   :        Ada.Streams.Stream_Element_Array) is
Begin
Declare
Subtype Selection is Stream_Element_Offset range
Stream.Position..Stream.Position+Stream_Element_Offset'Pred(Item'Length);
Begin
Stream.Data(Selection):= Item(Item'Range);
Stream.Position:= Stream_Element_Offset'Succ(Selection'Last);
End;
End Write;

----------------------------------
--  INITALIZER IMPLEMENTATIONS  --
----------------------------------
-- Create a buffer of the given length, zero-filled.
Function Buffer( Length : Natural ) return String_Stream is
Len : Constant Ada.Streams.Stream_Element_Offset :=
Ada.Streams.Stream_Element_Offset(Length);
Begin
Return Result : Constant String_Stream:=
(Root_Stream_Type with
Position =>  1,
Data     => (1..Len => 0),
Length   =>  Len
);
End Buffer;
-- Create a buffer from the given string.
Function From_String( Text : String ) return String_Stream is
Use Ada.Streams;
Subtype Element_Range is Stream_Element_Offset range
Stream_Element_Offset(Text'First)..Stream_Element_Offset(Text'Last);
Subtype Constrained_Array  is Stream_Element_Array(Element_Range);
Subtype Constrained_String is String(Text'Range);
Function Convert is new Ada.Unchecked_Conversion(
Source => Constrained_String,
Target => Constrained_Array
);
Begin
Return Result : Constant String_Stream:=
(Root_Stream_Type with
Position => Element_Range'First,
Data     => Convert( Text ),
Length   => Text'Length
);
End From_String;

-- Classwide returning renames, for consistancy/overload.
Function To_Stream( Text   : String  ) return Root_Stream_Class is
( From_String(Text) ) with Inline, Pure_Function;
Function To_Stream( Length : Natural ) return Root_Stream_Class is
( Buffer(Length)    ) with Inline, Pure_Function;

----------------------------
--  CONVERSION OPERATORS  --
----------------------------
-- Allocating / access-returning initalizing operations.
Function "+"( Length : Natural ) return not null access Root_Stream_Class is
( New Root_Stream_Class'(To_Stream(Length)) );
Function "+"( Text   : String  ) return not null access Root_Stream_Class is
( New Root_Stream_Class'(To_Stream(Text))   );
-- Conversion from text or integer to a stream; renaming of the initalizers.
Function "+"( Text   : String  ) return String_Stream renames From_String;
Function "+"( Length : Natural ) return String_Stream renames Buffer;
-- Convert a given Stream_Element_Array to a String.
Function "-"( Data   : Ada.Streams.Stream_Element_Array ) Return String is
Subtype Element_Range is Natural range
Natural(Data'First)..Natural(Data'Last);
Subtype Constrained_Array  is Stream_Element_Array(Data'Range);
Subtype Constrained_String is String(Element_Range);
Function Convert is new Ada.Unchecked_Conversion(
Source => Constrained_Array,
Target => Constrained_String
);
Begin
Return Convert( Data );
End "-";

----------------------
--  DATA RETRIEVAL  --
----------------------
Function "-"( Stream : String_Stream ) return String is
Begin
Return -Stream.Data(Stream.Position..Stream.Length);
End "-";

Function Data(Stream : String_Stream ) return String is
Begin
Return -Stream.Data;
End Data;

End Example;

最新更新