-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.go
More file actions
152 lines (119 loc) · 2.96 KB
/
parser.go
File metadata and controls
152 lines (119 loc) · 2.96 KB
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
package main
import (
"fmt"
"strconv"
)
func NewParser(input string) *Parser {
return &Parser{
lexer: NewLexer(input),
}
}
type Parser struct {
lexer *Lexer
}
func (p *Parser) Parse() (interface{}, error) {
var output interface{}
var err error
tok := p.lexer.NextToken()
output, err = p.ParseToken(tok)
tok = p.lexer.NextToken()
if tok.Type != EOF {
err = fmt.Errorf("expected end of input but found %s", tok.Literal)
}
return output, err
}
func (p *Parser) ParseObject(obj map[string]interface{}) (interface{}, error) {
var err error
// The BeginObject token is read in Parse, and given it has no use in our parsing
// other than to identify an object value, we immediately advance to the next token
tok := p.lexer.NextToken()
if tok.Type == EndObject {
return obj, err
}
// To iteratively parse multi-key objects, we loop until we don't find encounter
// the ValueSeparator token
for {
if tok.Type != String {
return obj, fmt.Errorf("expected key but found %s", tok.Literal)
}
key := tok.Literal
tok = p.lexer.NextToken()
if tok.Type != NameSeparator {
return obj, fmt.Errorf("expected name separate but found %s", tok.Literal)
}
tok = p.lexer.NextToken()
value, err := p.ParseToken(tok)
if err != nil {
return obj, err
}
obj[key] = value
tok = p.lexer.NextToken()
if tok.Type != ValueSeparator {
break
}
// We advance past the ValueSeparator token to arrive at the next
// key in the object
tok = p.lexer.NextToken()
}
if tok.Type != EndObject {
err = fmt.Errorf("expected } but found %s", tok.Literal)
}
return obj, err
}
func (p *Parser) ParseArray(arr []interface{}) (interface{}, error) {
var err error
tok := p.lexer.NextToken()
if tok.Type == EndArray {
return arr, err
}
// To iteratively parse arrays, we loop until we don't encounter
// the ValueSeparator token
for {
value, err := p.ParseToken(tok)
if err != nil {
return arr, err
}
arr = append(arr, value)
tok = p.lexer.NextToken()
if tok.Type != ValueSeparator {
break
}
// We advance past the ValueSeparator token to arrive at the next
// value in the array
tok = p.lexer.NextToken()
}
if tok.Type != EndArray {
err = fmt.Errorf("expected end of input but found %s", tok.Literal)
}
return arr, err
}
func (p *Parser) ParseToken(tok Token) (interface{}, error) {
var value interface{}
var err error
switch tok.Type {
case True:
value = true
case False:
value = false
case Null:
value = nil
case String:
value = tok.Literal
case Number:
value, err = strconv.ParseFloat(tok.Literal, 64)
if err != nil {
return value, err
}
case BeginObject:
value, err = p.ParseObject(make(map[string]interface{}))
case BeginArray:
value, err = p.ParseArray(make([]interface{}, 0))
case Illegal:
err = fmt.Errorf("illegal token %s encountered", tok.Literal)
case EOF:
err = fmt.Errorf("unexpected end of input")
default:
err = fmt.Errorf("unknown token %s", tok.Literal)
}
return value, err
}