-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjson-stream-parser.sml
152 lines (140 loc) · 4.6 KB
/
json-stream-parser.sml
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
(* json-stream-parser.sml
*
* COPYRIGHT (c) 2008 The Fellowship of SML/NJ (http://www.smlnj.org)
* All rights reserved.
*)
structure JSONStreamParser : sig
(* callback functions for the different parsing events *)
type 'a pos = ('a * AntlrStreamPos.sourcemap * AntlrStreamPos.span)
type 'ctx callbacks = {
null : 'ctx pos -> 'ctx,
boolean : 'ctx pos * bool -> 'ctx,
integer : 'ctx pos * IntInf.int -> 'ctx,
float : 'ctx pos * real -> 'ctx,
string : 'ctx pos * string -> 'ctx,
startObject : 'ctx pos -> 'ctx,
objectKey : 'ctx pos * string -> 'ctx,
endObject : 'ctx pos -> 'ctx,
startArray : 'ctx pos -> 'ctx,
endArray : 'ctx pos -> 'ctx,
error : 'ctx pos * string -> 'ctx
}
val parse : 'ctx callbacks -> (TextIO.instream * 'ctx) -> 'ctx
val parseFile : 'ctx callbacks -> (string * 'ctx) -> 'ctx
end = struct
structure Lex = JSONLexer
structure T = JSONTokens
(* callback functions for the different parsing events *)
type 'a pos = ('a * AntlrStreamPos.sourcemap * AntlrStreamPos.span)
type 'ctx callbacks = {
null : 'ctx pos -> 'ctx,
boolean : 'ctx pos * bool -> 'ctx,
integer : 'ctx pos * IntInf.int -> 'ctx,
float : 'ctx pos * real -> 'ctx,
string : 'ctx pos * string -> 'ctx,
startObject : 'ctx pos -> 'ctx,
objectKey : 'ctx pos * string -> 'ctx,
endObject : 'ctx pos -> 'ctx,
startArray : 'ctx pos -> 'ctx,
endArray : 'ctx pos -> 'ctx,
error : 'ctx pos * string -> 'ctx
}
fun error (cb : 'a callbacks, ctx, msg) = (
#error cb (ctx, msg);
raise Fail "error")
fun parser (cb : 'a callbacks) (srcMap, inStrm, ctx) = let
val smap = AntlrStreamPos.mkSourcemap ()
val lexer = Lex.lex smap
fun parseValue (strm : Lex.strm, ctx) = let
val (tok, pos, strm) = lexer strm
val ctx = (ctx, smap, pos)
in
case tok
of T.LB => parseArray (strm, #startArray cb ctx)
| T.LCB => parseObject (strm, #startObject cb ctx)
| T.KW_null => (strm, #null cb ctx)
| T.KW_true => (strm, #boolean cb (ctx, true))
| T.KW_false => (strm, #boolean cb (ctx, false))
| T.INT n => (strm, #integer cb (ctx, n))
| T.FLOAT f => (strm, #float cb (ctx, f))
| T.STRING s => (strm, #string cb (ctx, s))
| _ => error (cb, ctx, "error parsing value")
(* end case *)
end
and parseArray (strm : Lex.strm, ctx) = (case lexer strm
of (T.RB, pos, strm) => (strm, #endArray cb (ctx, smap, pos))
| _ => let
fun loop (strm, ctx) = let
val (strm, ctx) = parseValue (strm, ctx)
(* expect either a "," or a "]" *)
val (tok, pos, strm) = lexer strm
in
case tok
of T.RB => (strm, #endArray cb (ctx,smap,pos))
| T.COMMA => loop (strm, ctx)
| _ => error (cb, (ctx,smap,pos), "error parsing array")
(* end case *)
end
in
loop (strm, ctx)
end
(* end case *))
and parseObject (strm : Lex.strm, ctx) = let
fun parseField (strm, ctx) = (case lexer strm
of (T.STRING s, pos, strm) => let
val ctx = #objectKey cb ((ctx,smap,pos), s)
in
case lexer strm
of (T.COLON, _, strm) => parseValue (strm, ctx)
| (_,pos,_) =>
error (cb, (ctx,smap,pos), "error parsing field")
(* end case *)
end
| _ => (strm, ctx)
(* end case *))
fun loop (strm, ctx) = let
val (strm, ctx) = parseField (strm, ctx)
in
(* expect either "," or "}" *)
case lexer strm
of (T.RCB, pos, strm) => (strm, #endObject cb (ctx,smap,pos))
| (T.COMMA, pos, strm) => loop (strm, ctx)
| (_,pos,_) =>
error (cb, (ctx,smap,pos), "error parsing object")
(* end case *)
end
in
loop (strm, ctx)
end
val strm = Lex.streamifyInstream inStrm
val (tok1,pos,strm) = lexer strm
val ctx = (ctx,smap,pos)
val (_, finalctx) =
case tok1 of
T.LB => parseArray (strm, #startArray cb ctx)
| T.LCB => parseObject (strm, #startObject cb ctx)
| _ => error(cb, ctx, "JSON file must contain an array or object")
in
finalctx
end
fun parse cb = let
val parser = parser cb
fun parse' (inStrm, ctx) =
parser(AntlrStreamPos.mkSourcemap (), inStrm, ctx)
in
parse'
end
fun parseFile cb = let
val parser = parser cb
fun parse (fileName, ctx) = let
val inStrm = TextIO.openIn fileName
val ctx = parser (AntlrStreamPos.mkSourcemap' fileName, inStrm, ctx)
handle ex => (TextIO.closeIn inStrm; raise ex)
in
TextIO.closeIn inStrm;
ctx
end
in
parse
end
end