aboutsummaryrefslogtreecommitdiff
path: root/parser/states.go
blob: 92c80dceba4f9f04f484bc69e1e7e63d19cd3065 (plain) (blame)
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
package parser

func initJson(l *lexer) stateFunc {
	ignoreWhiteSpace(l)
	switch {
	case l.Accept("{"):
		l.Emit(lObjectStart)
		return stateInObject
	case l.Accept("["):
		l.Emit(lArrayStart)
	case l.Peek() == eof:
		return nil
	}
	return l.Errorf("Unknown token: %s", string(l.Peek()))
}

func stateInObject(l *lexer) stateFunc {
	// we in object, so we expect field keys and values
	ignoreWhiteSpace(l)
	if l.Accept("}") {
		l.Emit(lObjectEnd)
		// If meet close object return to previous state (including initial)
		return l.PopState()
	}
	ignoreWhiteSpace(l)
	l.Accept(",")
	ignoreWhiteSpace(l)
	if !scanQuotedString(l, '"') {
		return l.Errorf("Unknown token: %s", string(l.Peek()))
	}
	l.Emit(lObjectKey)
	ignoreWhiteSpace(l)
	if !l.Accept(":") {
		return l.Errorf("Expected ':'")
	}
	ignoreWhiteSpace(l)
	l.Emit(lObjectValue)
	switch {
	case scanQuotedString(l, '"'):
		l.Emit(lString)
		ignoreWhiteSpace(l)
		l.Accept(",")
		l.Ignore()
		ignoreWhiteSpace(l)
		return stateInObject
	case scanNumber(l):
		l.Emit(lNumber)
		ignoreWhiteSpace(l)
		l.Accept(",")
		l.Ignore()
		ignoreWhiteSpace(l)
		return stateInObject
	case l.AcceptAnyOf([]string{"true", "false"}, true):
		l.Emit(lBoolean)
		ignoreWhiteSpace(l)
		l.Accept(",")
		l.Ignore()
		ignoreWhiteSpace(l)
		return stateInObject
	case l.AcceptString("null", true):
		l.Emit(lNull)
		ignoreWhiteSpace(l)
		l.Accept(",")
		l.Ignore()
		ignoreWhiteSpace(l)
		return stateInObject
	case l.Accept("{"):
		l.Emit(lObjectStart)
		l.PushState(stateInObject)
		return stateInObject
	case l.Accept("["):
		l.Emit(lArrayStart)
		l.PushState(stateInObject)
		return stateInArray
	}
	return l.Errorf("Unknown token: %s", string(l.Peek()))
}

func stateInArray(l *lexer) stateFunc {
	ignoreWhiteSpace(l)
	l.Accept(",")
	ignoreWhiteSpace(l)
	switch {
	case scanQuotedString(l, '"'):
		l.Emit(lString)
	case scanNumber(l):
		l.Emit(lNumber)
	case l.AcceptAnyOf([]string{"true", "false"}, true):
		l.Emit(lBoolean)
	case l.AcceptString("null", true):
		l.Emit(lNull)
	case l.Accept("{"):
		l.Emit(lObjectStart)
		l.PushState(stateInArray)
		return stateInObject
	case l.Accept("["):
		l.Emit(lArrayStart)
		l.PushState(stateInArray)
		return stateInArray
	case l.Accept("]"):
		l.Emit(lArrayEnd)
		return l.PopState()
	}
	return stateInArray
}

func ignoreWhiteSpace(l *lexer) {
	l.AcceptWhile(" \n\t") // ignore whitespaces
	l.Ignore()
}