Source file parser_stream.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
module type Parser = sig
module Compliance : Compliance.S
type t
val create : reader : (unit -> Tokens.token) -> t
val decode : t -> (Compliance.json_stream option, string) result
end
module Make (Compliance : Compliance.S) : Parser
with module Compliance = Compliance
= struct
module Compliance = Compliance
exception Parse_error of [`Eof | `Syntax_error of string]
type t = {
reader : unit -> Tokens.token
; continuation : (unit -> Compliance.json_stream) Stack.t
; state : [`Start | `Process | `End] ref
}
let create ~reader =
{
reader
; continuation = Stack.create ()
; state = ref `Start
}
let json_stream t =
let open Tokens in
let open Parser_tools in
let rec token_value tok = begin
match tok with
| INT i -> Compliance.Stream.integer i
| STRING s -> Compliance.Stream.string s
| BOOL b -> Compliance.Stream.bool b
| FLOAT f -> Compliance.Stream.number (`Float f)
| INFINITY -> Compliance.Stream.number `Infinity
| NEGINFINITY -> Compliance.Stream.number `Neginfinity
| NAN -> Compliance.Stream.number `Nan
| NULL -> Compliance.Stream.null
| LARGEINT s -> Compliance.Stream.largeint s
| EOF -> raise (Parse_error `Eof)
| COMMA | COLON | AE | OE | TE | VE | LEX_ERROR _ | COMPLIANCE_ERROR _ ->
raise (Parse_error (token_error tok))
| AS -> Stack.push array_value t.continuation; Compliance.Stream.array_start ()
| OS -> Stack.push object_value t.continuation; Compliance.Stream.object_start ()
| TS -> Stack.push tuple_value t.continuation; Compliance.Stream.tuple_start ()
| VS -> Stack.push variant_value t.continuation; Compliance.Stream.variant_start ()
end
and array_value () = begin
let tok = t.reader () in
match tok with
| AE -> Compliance.Stream.array_end ()
| tok -> Stack.push array_value_next t.continuation; token_value tok
end
and array_value_next () = begin
match t.reader () with
| AE -> Compliance.Stream.array_end ()
| COMMA ->
let tok = t.reader () in
Stack.push array_value_next t.continuation;
token_value tok
| tok -> raise (Parse_error (token_error tok))
end
and object_value () = begin
let tok = t.reader () in
match tok with
| OE -> Compliance.Stream.object_end ()
| STRING s -> Stack.push object_colon_value t.continuation; Compliance.Stream.name s
| tok -> raise (Parse_error (token_error tok))
end
and object_colon_value () = begin
match t.reader () with
| COLON ->
let tok = t.reader () in
Stack.push object_value_next t.continuation;
token_value tok
| tok -> raise (Parse_error (token_error tok))
end
and object_value_next () = begin
match t.reader () with
| OE -> Compliance.Stream.object_end ()
| COMMA -> begin
match t.reader () with
| STRING s -> Stack.push object_colon_value t.continuation; Compliance.Stream.name s
| tok -> raise (Parse_error (token_error tok))
end
| tok -> raise (Parse_error (token_error tok))
end
and tuple_value () = begin
let tok = t.reader () in
match tok with
| TE -> raise (Parse_error (`Syntax_error "tuple must have at least 2 elements"))
| tok -> Stack.push tuple_value_1 t.continuation; token_value tok
end
and tuple_value_1 () = begin
match t.reader () with
| TE -> raise (Parse_error (`Syntax_error "tuple must have at least 2 elements"))
| COMMA ->
let tok = t.reader () in
Stack.push tuple_value_2 t.continuation;
token_value tok
| tok -> raise (Parse_error (token_error tok))
end
and tuple_value_2 () = begin
match t.reader () with
| TE -> Compliance.Stream.tuple_end ()
| COMMA ->
let tok = t.reader () in
Stack.push tuple_value_2 t.continuation;
token_value tok
| tok -> raise (Parse_error (token_error tok))
end
and variant_value () = begin
match t.reader () with
| STRING s -> Stack.push variant_colon_or_end t.continuation; Compliance.Stream.name s
| tok -> raise (Parse_error (token_error tok))
end
and variant_colon_or_end () = begin
match t.reader () with
| VE -> Compliance.Stream.variant_end ()
| COLON ->
let tok = t.reader () in
Stack.push variant_end t.continuation;
token_value tok
| tok -> raise (Parse_error (token_error tok))
end
and variant_end () = begin
match t.reader () with
| VE -> Compliance.Stream.variant_end ()
| tok -> raise (Parse_error (token_error tok))
end
in
if Stack.is_empty t.continuation then begin
match t.reader () with
| exception (Parse_error `Eof) -> None
| exception exn_ -> raise exn_
| tok -> begin
match tok with
| EOF -> None
| tok -> Some (token_value tok)
end
end
else Some ((Stack.pop t.continuation) ())
let decode t =
let handle_eof () =
if Stack.length t.continuation > 0 then Error "unexpected end-of-input"
else begin
match !(t.state) with
| `Start -> Error "empty input"
| `Process
| `End -> Ok None
end
in
match json_stream t with
| exception (Parse_error (`Syntax_error err)) -> Error err
| exception (Lexxer_utils.Lex_error err) -> Error err
| exception (Parse_error `Eof) -> handle_eof ()
| None -> handle_eof ()
| res ->
match !(t.state) with
| `Start -> t.state := `Process; Ok res
| `Process -> if Stack.length t.continuation = 0 then t.state := `End; Ok res
| `End -> Error "Junk following JSON value"
end