/
parser.cr
137 lines (110 loc) · 2.53 KB
/
parser.cr
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
require "./lexer"
class JSON::Parser
property max_nesting = 512
def initialize(string_or_io : String | IO)
@lexer = JSON::Lexer.new(string_or_io)
@nest = 0
next_token
end
def parse : Any
json = parse_value
check :EOF
json
end
private def parse_value
case token.kind
when .int?
value_and_next_token token.int_value
when .float?
value_and_next_token token.float_value
when .string?
value_and_next_token token.string_value
when .null?
value_and_next_token nil
when .true?
value_and_next_token true
when .false?
value_and_next_token false
when .begin_array?
parse_array
when .begin_object?
parse_object
else
unexpected_token
end
end
private def parse_array
next_token
ary = [] of Any
nest do
unless token.kind.end_array?
while true
ary << parse_value
case token.kind
when .comma?
next_token
unexpected_token if token.kind.end_array?
when .end_array?
break
else
unexpected_token
end
end
end
end
next_token
Any.new(ary)
end
private def parse_object
next_token_expect_object_key
object = {} of String => Any
nest do
unless token.kind.end_object?
while true
check :string
key = token.string_value
next_token
check :colon
next_token
value = parse_value
object[key] = value
case token.kind
when .comma?
next_token_expect_object_key
unexpected_token if token.kind.end_object?
when .end_object?
break
else
unexpected_token
end
end
end
end
next_token
Any.new(object)
end
private delegate token, to: @lexer
private delegate next_token, to: @lexer
private delegate next_token_expect_object_key, to: @lexer
private def value_and_next_token(value)
next_token
Any.new(value)
end
private def check(kind : Token::Kind)
unexpected_token unless token.kind == kind
end
private def unexpected_token
parse_exception "unexpected token '#{token}'"
end
private def parse_exception(msg)
raise ParseException.new(msg, token.line_number, token.column_number)
end
private def nest
@nest += 1
if @nest > @max_nesting
parse_exception "Nesting of #{@nest} is too deep"
end
yield
@nest -= 1
end
end