Guide · Parsing

Incremental parsing

The parser accepts any chunk schedule. It retains lexical and structural state, but it never retains a reference to the caller's input array.

Parse one complete value

Flyology JSON has no default profile or capacity. This complete strict scalar example sets each value explicitly, initializes the parser, and checks complete-document acceptance.

   declare
      Quick_Profile : constant Profiles.Parser_Profile :=
        (Syntax        => (Family => Profiles.RFC_8259, Version => 1),
         Unicode       => (Family => Profiles.Unicode_Scalars, Version => 1),
         Compatibility => (Family => Profiles.No_Extensions, Version => 1),
         BOM           => Profiles.Reject_BOM,
         Duplicates    => Profiles.Reject_Duplicates,
         Top_Level     => Profiles.Accept_Any_Value);
      Quick_Parser : Parsing.Parser
        (Maximum_Depth       => 0,
         Name_Octet_Capacity => 0,
         Name_Capacity       => 0);
      Input : constant Ada.Streams.Stream_Element_Array :=
        [Character'Pos ('n'), Character'Pos ('u'), Character'Pos ('l'), Character'Pos ('l')];
      Quick_Events     : Parsing.Event_Array (1 .. 4);
      Quick_Result     : Parsing.Drain_Result;
      Quick_Diagnostic : Errors.Diagnostic;
   begin
      Parsing.Initialize (Quick_Parser, Quick_Profile, Quick_Diagnostic);
      if Quick_Diagnostic.Code /= Errors.No_Error then
         raise Program_Error with "parser initialization failed";
      end if;

      Parsing.Drain
        (Self         => Quick_Parser,
         Input        => Input,
         End_Of_Input => True,
         Events       => Quick_Events,
         Result       => Quick_Result);
      if Quick_Result.Stop /= Parsing.Drain_Document_Complete then
         raise Program_Error with "JSON document was not accepted";
      end if;
   end;

Run the complete examples with ./scripts/test-examples.sh. The maintained streaming_parser.adb source contains the complete arbitrary-chunk loop.

Choose a static duplicate policy

Instantiate Flyology_JSON.Parsing with one explicit duplicate policy. The generic has no default.

Reject_Duplicates compares decoded UTF-8 names without normalization. It uses caller-backed name storage and a bounded crit-bit index. Detection occurs when the later name ends, and the diagnostic blames its opening quote.

Preserve_Unchecked emits every member in source order. It stores no duplicate-name state and does not choose a first or last value.

!

Duplicate JSON names and application aliases are different checks.

An application adapter still detects two different names that map to one application field.

Configure physical storage

A Parser takes three discriminants. They are capacities, not compatibility policy, and the library supplies no defaults.

CapacityExact unit
Maximum_DepthSimultaneously open objects and arrays. A root container is depth one.
Name_Octet_CapacityDecoded UTF-8 octets retained across all open strict objects plus the active candidate.
Name_CapacityStrict duplicate-index leaves and internal nodes retained across open objects.

Preserve mode ignores both name capacities, so an application can set them to zero. A scalar root needs depth zero.

Drive one event or a batch

Step returns one event, a request for input, complete-document acceptance, or a failure. Drain uses the same engine and fills an arbitrary-bound caller event array.

1. InitializeFreeze an explicit profile before byte zero.
2. Supply inputPass a chunk and its final-input state.
3. ConsumeAdvance by the returned count from Input'First.
4. RepeatKeep final input true after the parser latches it.

Need_Input consumes the complete supplied chunk. A nonnull Output_Full result fills the complete event array. A null event array is a nonmutating capacity stop.

When a call admits End_Of_Input = True, later calls for that document must keep it true. Retraction fails without consuming input.

Read the closed event grammar

The Event_Kind sequence is balanced and JSON-specific. Objects and arrays do not report lengths. Names, strings, and numbers use begin, fragment, and end events.

  • Number fragments preserve exact source octets and have no token-storage length ceiling, subject to coordinate exhaustion.
  • Decoded name and string fragments end at Unicode scalar boundaries.
  • An escape or surrogate pair can produce an inline decoded scalar with complete source provenance.
  • A copied event retains coordinates and inline scalar bytes, but never an input reference.

Null and Boolean events expose the complete raw literal only when that literal fits in the producing input window. A split literal remains valid without such a slice.

Resolve a raw range in the producing call

Resolve_Raw_Range maps absolute source coordinates into the current input window. It validates coordinate containment only. It cannot authenticate an Ada array's identity or unchanged contents.

Use the exact unchanged input actual from the call that produced the event. If a consumer must retain a range, copy it before the producing call returns. Do not attach an event to a later chunk that happens to have the same bounds.

0

All public offsets are zero-based octet coordinates.

Consumed, produced, and raw-slice positions are counts from the corresponding array's first bound.

Accept only after document completion

Every event is a provisional observation. The parser accepts the complete document only when a call returns Document_Complete after Document_End.

A consumer can commit its private candidate at that gate. On malformed input or resource failure, the consumer aborts its candidate and then resets or discards the parser.

Abort_Document ends a clean active operation without raising. A retained primary failure remains primary. Reset starts a new operation at byte zero only from a terminal state and revalidates the complete profile.